back-end done
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
# Created by .ignore support plugin (hsz.mobi)
|
||||
### Node template
|
||||
/static/uploads
|
||||
# Logs
|
||||
/logs
|
||||
*.log
|
||||
|
||||
+2
-25
@@ -1,10 +1,10 @@
|
||||
const jwt = require('jsonwebtoken');
|
||||
const Admin = require('./models/admin/Admin')
|
||||
const User = require('./models/user/User')
|
||||
|
||||
|
||||
const config = {
|
||||
// secret for generating jwt token
|
||||
secretKey: '2664debdbef6fdd2ae52ba2c9cd4d1d15f3cdca31a641aacad1a5c43cda91b55a145b3f4c573f69aeba3c942bf55417593ff74f7d192a5664358ee753ea09e8e'
|
||||
secretKey: 'b8a537eefc8e8e938509bd6a557e51d8f9459842691b013254fb8f31e6d6c78713f65fad589f0b036481907b7014e249d28da1ea359f8a5b7f59da3aa5b0455f'
|
||||
}
|
||||
|
||||
module.exports = config
|
||||
@@ -31,26 +31,3 @@ module.exports.isAdmin = function (req, res, next) {
|
||||
return res.status(401).json({message: 'unauthorized'})
|
||||
}
|
||||
}
|
||||
|
||||
// check if user logged in
|
||||
module.exports.isUser = function (req, res, next) {
|
||||
const token = req.headers.authorization
|
||||
if (token) {
|
||||
// check if token is not destroyed
|
||||
User.findOne({token: token}, (err, user) => {
|
||||
if (err) throw err
|
||||
if (user) {
|
||||
// verifies secret and checks if the token is expired
|
||||
jwt.verify(user.token.replace(/^Bearer\s/, ''), config.secretKey, (err, decoded) => {
|
||||
if (err) {
|
||||
return res.status(401).json({message: 'unauthorized'})
|
||||
} else {
|
||||
return next()
|
||||
}
|
||||
})
|
||||
} else return res.status(401).json({message: 'unauthorized'})
|
||||
})
|
||||
} else {
|
||||
return res.status(401).json({message: 'unauthorized'})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,385 +0,0 @@
|
||||
const AboutPageContent = require('../models/AboutPageContent')
|
||||
const dateformat = require('dateformat')
|
||||
const {body, validationResult} = require('express-validator')
|
||||
const jimp = require('jimp')
|
||||
const fs = require('fs')
|
||||
|
||||
module.exports.create = [
|
||||
[
|
||||
// fa
|
||||
body('fa_page_title')
|
||||
.notEmpty().withMessage('تیتر بالای صفحه نباید خالی باشد.'),
|
||||
body('fa_s1_title')
|
||||
.notEmpty().withMessage('تیتر بخش اول نباید خالی باشد.'),
|
||||
body('fa_s1_caption')
|
||||
.notEmpty().withMessage('توضیحات بخش اول نباید خالی باشد.'),
|
||||
body('fa_s2_title')
|
||||
.notEmpty().withMessage('تیتر بخش دوم نباید خالی باشد.'),
|
||||
body('fa_s2_caption')
|
||||
.notEmpty().withMessage('توضیحات بخش دوم نباید خالی باشد.'),
|
||||
body('fa_s2_imageCaption')
|
||||
.notEmpty().withMessage('توضیحات عکس بخش دوم نباید خالی باشد.'),
|
||||
body('fa_s3_title')
|
||||
.notEmpty().withMessage('تیتر بخش سوم نباید خالی باشد.'),
|
||||
body('fa_s3_caption')
|
||||
.notEmpty().withMessage('توضیحات بخش سوم نباید خالی باشد.'),
|
||||
body('fa_s3_imageCaption')
|
||||
.notEmpty().withMessage('توضیحات عکس بخش سوم نباید خالی باشد.'),
|
||||
body('fa_s4_text')
|
||||
.notEmpty().withMessage('متن بخش چهارم نباید خالی باشد.'),
|
||||
body('fa_last_section_title')
|
||||
.notEmpty().withMessage('تیتر بخش آخر نباید خالی باشد.'),
|
||||
body('fa_last_section_text')
|
||||
.notEmpty().withMessage('متن بخش آخر نباید خالی باشد.'),
|
||||
|
||||
// en
|
||||
body('en_page_title')
|
||||
.notEmpty().withMessage('تیتر بالای صفحه نباید خالی باشد.'),
|
||||
body('en_s1_title')
|
||||
.notEmpty().withMessage('تیتر بخش اول نباید خالی باشد.'),
|
||||
body('en_s1_caption')
|
||||
.notEmpty().withMessage('توضیحات بخش اول نباید خالی باشد.'),
|
||||
body('en_s2_title')
|
||||
.notEmpty().withMessage('تیتر بخش دوم نباید خالی باشد.'),
|
||||
body('en_s2_caption')
|
||||
.notEmpty().withMessage('توضیحات بخش دوم نباید خالی باشد.'),
|
||||
body('en_s2_imageCaption')
|
||||
.notEmpty().withMessage('توضیحات عکس بخش دوم نباید خالی باشد.'),
|
||||
body('en_s3_title')
|
||||
.notEmpty().withMessage('تیتر بخش سوم نباید خالی باشد.'),
|
||||
body('en_s3_caption')
|
||||
.notEmpty().withMessage('توضیحات بخش سوم نباید خالی باشد.'),
|
||||
body('en_s3_imageCaption')
|
||||
.notEmpty().withMessage('توضیحات عکس بخش سوم نباید خالی باشد.'),
|
||||
body('en_s4_text')
|
||||
.notEmpty().withMessage('متن بخش چهارم نباید خالی باشد.'),
|
||||
body('en_last_section_title')
|
||||
.notEmpty().withMessage('تیتر بخش آخر نباید خالی باشد.'),
|
||||
body('en_last_section_text')
|
||||
.notEmpty().withMessage('متن بخش آخر نباید خالی باشد.'),
|
||||
|
||||
// de
|
||||
body('de_page_title')
|
||||
.notEmpty().withMessage('تیتر بالای صفحه نباید خالی باشد.'),
|
||||
body('de_s1_title')
|
||||
.notEmpty().withMessage('تیتر بخش اول نباید خالی باشد.'),
|
||||
body('de_s1_caption')
|
||||
.notEmpty().withMessage('توضیحات بخش اول نباید خالی باشد.'),
|
||||
body('de_s2_title')
|
||||
.notEmpty().withMessage('تیتر بخش دوم نباید خالی باشد.'),
|
||||
body('de_s2_caption')
|
||||
.notEmpty().withMessage('توضیحات بخش دوم نباید خالی باشد.'),
|
||||
body('de_s2_imageCaption')
|
||||
.notEmpty().withMessage('توضیحات عکس بخش دوم نباید خالی باشد.'),
|
||||
body('de_s3_title')
|
||||
.notEmpty().withMessage('تیتر بخش سوم نباید خالی باشد.'),
|
||||
body('de_s3_caption')
|
||||
.notEmpty().withMessage('توضیحات بخش سوم نباید خالی باشد.'),
|
||||
body('de_s3_imageCaption')
|
||||
.notEmpty().withMessage('توضیحات عکس بخش سوم نباید خالی باشد.'),
|
||||
body('de_s4_text')
|
||||
.notEmpty().withMessage('متن بخش چهارم نباید خالی باشد.'),
|
||||
body('de_last_section_title')
|
||||
.notEmpty().withMessage('تیتر بخش آخر نباید خالی باشد.'),
|
||||
body('de_last_section_text')
|
||||
.notEmpty().withMessage('متن بخش آخر نباید خالی باشد.'),
|
||||
|
||||
// tr
|
||||
body('tr_page_title')
|
||||
.notEmpty().withMessage('تیتر بالای صفحه نباید خالی باشد.'),
|
||||
body('tr_s1_title')
|
||||
.notEmpty().withMessage('تیتر بخش اول نباید خالی باشد.'),
|
||||
body('tr_s1_caption')
|
||||
.notEmpty().withMessage('توضیحات بخش اول نباید خالی باشد.'),
|
||||
body('tr_s2_title')
|
||||
.notEmpty().withMessage('تیتر بخش دوم نباید خالی باشد.'),
|
||||
body('tr_s2_caption')
|
||||
.notEmpty().withMessage('توضیحات بخش دوم نباید خالی باشد.'),
|
||||
body('tr_s2_imageCaption')
|
||||
.notEmpty().withMessage('توضیحات عکس بخش دوم نباید خالی باشد.'),
|
||||
body('tr_s3_title')
|
||||
.notEmpty().withMessage('تیتر بخش سوم نباید خالی باشد.'),
|
||||
body('tr_s3_caption')
|
||||
.notEmpty().withMessage('توضیحات بخش سوم نباید خالی باشد.'),
|
||||
body('tr_s3_imageCaption')
|
||||
.notEmpty().withMessage('توضیحات عکس بخش سوم نباید خالی باشد.'),
|
||||
body('tr_s4_text')
|
||||
.notEmpty().withMessage('متن بخش چهارم نباید خالی باشد.'),
|
||||
body('tr_last_section_title')
|
||||
.notEmpty().withMessage('تیتر بخش آخر نباید خالی باشد.'),
|
||||
body('tr_last_section_text')
|
||||
.notEmpty().withMessage('متن بخش آخر نباید خالی باشد.'),
|
||||
|
||||
// it
|
||||
body('it_page_title')
|
||||
.notEmpty().withMessage('تیتر بالای صفحه نباید خالی باشد.'),
|
||||
body('it_s1_title')
|
||||
.notEmpty().withMessage('تیتر بخش اول نباید خالی باشد.'),
|
||||
body('it_s1_caption')
|
||||
.notEmpty().withMessage('توضیحات بخش اول نباید خالی باشد.'),
|
||||
body('it_s2_title')
|
||||
.notEmpty().withMessage('تیتر بخش دوم نباید خالی باشد.'),
|
||||
body('it_s2_caption')
|
||||
.notEmpty().withMessage('توضیحات بخش دوم نباید خالی باشد.'),
|
||||
body('it_s2_imageCaption')
|
||||
.notEmpty().withMessage('توضیحات عکس بخش دوم نباید خالی باشد.'),
|
||||
body('it_s3_title')
|
||||
.notEmpty().withMessage('تیتر بخش سوم نباید خالی باشد.'),
|
||||
body('it_s3_caption')
|
||||
.notEmpty().withMessage('توضیحات بخش سوم نباید خالی باشد.'),
|
||||
body('it_s3_imageCaption')
|
||||
.notEmpty().withMessage('توضیحات عکس بخش سوم نباید خالی باشد.'),
|
||||
body('it_s4_text')
|
||||
.notEmpty().withMessage('متن بخش چهارم نباید خالی باشد.'),
|
||||
body('it_last_section_title')
|
||||
.notEmpty().withMessage('تیتر بخش آخر نباید خالی باشد.'),
|
||||
body('it_last_section_text')
|
||||
.notEmpty().withMessage('متن بخش آخر نباید خالی باشد.'),
|
||||
|
||||
],
|
||||
(req, res) => {
|
||||
// check validations
|
||||
const errors = validationResult(req)
|
||||
if (!errors.isEmpty()) return res.status(422).json({validation: errors.mapped()})
|
||||
|
||||
|
||||
////////////////// catch form data
|
||||
const data = {
|
||||
aboutPage_details: {
|
||||
fa: {
|
||||
page_title: req.body.fa_page_title,
|
||||
s1_title: req.body.fa_s1_title,
|
||||
s1_caption: req.body.fa_s1_caption,
|
||||
s2_title: req.body.fa_s2_title,
|
||||
s2_caption: req.body.fa_s2_caption,
|
||||
s2_imageCaption: req.body.fa_s2_imageCaption,
|
||||
s3_title: req.body.fa_s3_title,
|
||||
s3_caption: req.body.fa_s3_caption,
|
||||
s3_imageCaption: req.body.fa_s3_imageCaption,
|
||||
s4_text: req.body.fa_s4_text,
|
||||
last_section_title: req.body.fa_last_section_title,
|
||||
last_section_text: req.body.fa_last_section_text
|
||||
},
|
||||
en: {
|
||||
page_title: req.body.en_page_title,
|
||||
s1_title: req.body.en_s1_title,
|
||||
s1_caption: req.body.en_s1_caption,
|
||||
s2_title: req.body.en_s2_title,
|
||||
s2_caption: req.body.en_s2_caption,
|
||||
s2_imageCaption: req.body.en_s2_imageCaption,
|
||||
s3_title: req.body.en_s3_title,
|
||||
s3_caption: req.body.en_s3_caption,
|
||||
s3_imageCaption: req.body.en_s3_imageCaption,
|
||||
s4_text: req.body.en_s4_text,
|
||||
last_section_title: req.body.en_last_section_title,
|
||||
last_section_text: req.body.en_last_section_text
|
||||
},
|
||||
de: {
|
||||
page_title: req.body.de_page_title,
|
||||
s1_title: req.body.de_s1_title,
|
||||
s1_caption: req.body.de_s1_caption,
|
||||
s2_title: req.body.de_s2_title,
|
||||
s2_caption: req.body.de_s2_caption,
|
||||
s2_imageCaption: req.body.de_s2_imageCaption,
|
||||
s3_title: req.body.de_s3_title,
|
||||
s3_caption: req.body.de_s3_caption,
|
||||
s3_imageCaption: req.body.de_s3_imageCaption,
|
||||
s4_text: req.body.de_s4_text,
|
||||
last_section_title: req.body.de_last_section_title,
|
||||
last_section_text: req.body.de_last_section_text
|
||||
},
|
||||
tr: {
|
||||
page_title: req.body.tr_page_title,
|
||||
s1_title: req.body.tr_s1_title,
|
||||
s1_caption: req.body.tr_s1_caption,
|
||||
s2_title: req.body.tr_s2_title,
|
||||
s2_caption: req.body.tr_s2_caption,
|
||||
s2_imageCaption: req.body.tr_s2_imageCaption,
|
||||
s3_title: req.body.tr_s3_title,
|
||||
s3_caption: req.body.tr_s3_caption,
|
||||
s3_imageCaption: req.body.tr_s3_imageCaption,
|
||||
s4_text: req.body.tr_s4_text,
|
||||
last_section_title: req.body.tr_last_section_title,
|
||||
last_section_text: req.body.tr_last_section_text
|
||||
},
|
||||
it: {
|
||||
page_title: req.body.it_page_title,
|
||||
s1_title: req.body.it_s1_title,
|
||||
s1_caption: req.body.it_s1_caption,
|
||||
s2_title: req.body.it_s2_title,
|
||||
s2_caption: req.body.it_s2_caption,
|
||||
s2_imageCaption: req.body.it_s2_imageCaption,
|
||||
s3_title: req.body.it_s3_title,
|
||||
s3_caption: req.body.it_s3_caption,
|
||||
s3_imageCaption: req.body.it_s3_imageCaption,
|
||||
s4_text: req.body.it_s4_text,
|
||||
last_section_title: req.body.it_last_section_title,
|
||||
last_section_text: req.body.it_last_section_text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function createImages(image, imageName) {
|
||||
if (image) {
|
||||
jimp.read(image.data)
|
||||
.then(img => {
|
||||
img
|
||||
.cover(380, 510)
|
||||
.write(`./static/uploads/images/about/${imageName}`, (err, file) => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
let heroFile
|
||||
let heroFileName
|
||||
let s2File
|
||||
let s2FileName
|
||||
let s3File
|
||||
let s3FileName
|
||||
let lastSectionFile
|
||||
let lastSectionFileName
|
||||
|
||||
if (req.files) {
|
||||
if (req.files.page_hero) {
|
||||
heroFile = req.files.page_hero
|
||||
heroFileName = 'image_' + Date.now() + 1 + '.' + heroFile.mimetype.split('/')[1]
|
||||
}
|
||||
if (req.files.s2_image) {
|
||||
s2File = req.files.s2_image
|
||||
s2FileName = 'image_' + Date.now() + 2 + '.' + s2File.mimetype.split('/')[1]
|
||||
}
|
||||
if (req.files.s3_image) {
|
||||
s3File = req.files.s3_image
|
||||
s3FileName = 'image_' + Date.now() + 3 + '.' + s3File.mimetype.split('/')[1]
|
||||
}
|
||||
if (req.files.last_section_image) {
|
||||
lastSectionFile = req.files.last_section_image
|
||||
lastSectionFileName = 'image_' + Date.now() + 4 + '.' + lastSectionFile.mimetype.split('/')[1]
|
||||
}
|
||||
}
|
||||
|
||||
/////////////// save to database
|
||||
if (req.body._id) {
|
||||
if (req.files) {
|
||||
if (heroFile) {
|
||||
if (heroFile.size / 1024 > 500) return res.status(422).json({validation: {page_hero: {msg: 'حجم عکس نباید بیشتر از 500 کیلوبایت باشد.'}}})
|
||||
data.page_hero = heroFileName
|
||||
heroFile.mv(`./static/uploads/images/about/${heroFileName}`, err => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
}
|
||||
|
||||
if (s2File) {
|
||||
data.s2_image = s2FileName
|
||||
createImages(s2File, s2FileName)
|
||||
}
|
||||
|
||||
if (s3File) {
|
||||
data.s3_image = s3FileName
|
||||
createImages(s3File, s3FileName)
|
||||
}
|
||||
|
||||
if (lastSectionFile) {
|
||||
if (lastSectionFile.size / 1024 > 500) return res.status(422).json({validation: {last_section_image: {msg: 'حجم عکس نباید بیشتر از 500 کیلوبایت باشد.'}}})
|
||||
data.last_section_image = lastSectionFileName
|
||||
lastSectionFile.mv(`./static/uploads/images/about/${lastSectionFileName}`, err => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
}
|
||||
}
|
||||
data.updated_at = dateformat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
|
||||
AboutPageContent.findByIdAndUpdate(req.body._id, data, (err, oldData) => {
|
||||
if (err) console.log(err)
|
||||
if (req.files) {
|
||||
if (heroFile) {
|
||||
fs.unlink(`./static/${oldData.page_hero}`, err => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
}
|
||||
if (s2File) {
|
||||
fs.unlink(`./static/${oldData.s2_image}`, err => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
}
|
||||
if (s3File) {
|
||||
fs.unlink(`./static/${oldData.s3_image}`, err => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
}
|
||||
if (lastSectionFile) {
|
||||
fs.unlink(`./static/${oldData.last_section_image}`, err => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
}
|
||||
}
|
||||
AboutPageContent.findByIdAndUpdate(req.body._id)
|
||||
.then(data => {
|
||||
return res.json(data)
|
||||
})
|
||||
})
|
||||
} else {
|
||||
if (req.files) {
|
||||
if (heroFile) {
|
||||
if (heroFile.size / 1024 > 500) return res.status(422).json({validation: {page_hero: {msg: 'حجم عکس نباید بیشتر از 500 کیلوبایت باشد.'}}})
|
||||
data.page_hero = heroFileName
|
||||
heroFile.mv(`./static/uploads/images/about/${heroFileName}`, err => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
} else {
|
||||
return res.status(422).json({validation: {page_hero: {msg: 'عکس بخش اول اجباری است.'}}})
|
||||
}
|
||||
|
||||
if (s2File) {
|
||||
data.s2_image = s2FileName
|
||||
createImages(s2File, s2FileName)
|
||||
} else {
|
||||
return res.status(422).json({validation: {s2_image: {msg: 'عکس بخش دوم اجباری است.'}}})
|
||||
}
|
||||
|
||||
if (s3File) {
|
||||
data.s3_image = s3FileName
|
||||
createImages(s3File, s3FileName)
|
||||
} else {
|
||||
return res.status(422).json({validation: {s3_image: {msg: 'عکس بخش سوم اجباری است.'}}})
|
||||
}
|
||||
|
||||
if (lastSectionFile) {
|
||||
if (lastSectionFile.size / 1024 > 500) return res.status(422).json({validation: {last_section_image: {msg: 'حجم عکس نباید بیشتر از 500 کیلوبایت باشد.'}}})
|
||||
data.last_section_image = lastSectionFileName
|
||||
lastSectionFile.mv(`./static/uploads/images/about/${lastSectionFileName}`, err => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
} else {
|
||||
return res.status(422).json({validation: {last_section_image: {msg: 'عکس بخش آخر اجباری است.'}}})
|
||||
}
|
||||
} else {
|
||||
return res.status(422).json({
|
||||
validation: {
|
||||
page_hero: {msg: 'عکس بخش اول اجباری است.'},
|
||||
s2_image: {msg: 'عکس بخش دوم اجباری است.'},
|
||||
s3_image: {msg: 'عکس بخش سوم اجباری است.'},
|
||||
last_section_image: {msg: 'عکس بخش آخر اجباری است.'}
|
||||
}
|
||||
})
|
||||
}
|
||||
data.created_at = dateformat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
|
||||
const aboutContent = new AboutPageContent(data)
|
||||
aboutContent.save((err, data) => {
|
||||
if (err) return res.status(500).json(err)
|
||||
return res.json(data)
|
||||
})
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
module.exports.get = [
|
||||
(req, res) => {
|
||||
AboutPageContent.findOne({}, (err, data) => {
|
||||
if (err) return res.status(404).json({message: err})
|
||||
return res.json(data)
|
||||
})
|
||||
}
|
||||
]
|
||||
@@ -4,28 +4,30 @@ const dateformat = require('dateformat')
|
||||
const bcrypt = require('bcryptjs')
|
||||
const jwt = require('jsonwebtoken')
|
||||
const config = require('../config')
|
||||
const v_m = require('../validation_messages')
|
||||
|
||||
/////////////////////////////////////////////////////////////////////// register
|
||||
module.exports.register = [
|
||||
[
|
||||
body('name')
|
||||
.isLength({min: 4}).withMessage('حداقل 4 کاراکتر'),
|
||||
.isLength({min: 2}).withMessage(v_m['fa'].min_char.min2),
|
||||
|
||||
body('username')
|
||||
.isLength({min: 4}).withMessage('حداقل 4 کاراکتر')
|
||||
.isLength({min: 4}).withMessage(v_m['fa'].min_char.min4)
|
||||
.custom((value, {req}) => {
|
||||
return Admin.findOne({username: value})
|
||||
.then(admin => {
|
||||
if (admin && admin.username === value) return Promise.reject('این نام کاربری از قبل وجود دارد.')
|
||||
if (admin && admin.username === value) return Promise.reject(v_m['fa'].duplicated.username)
|
||||
else return true
|
||||
})
|
||||
}),
|
||||
|
||||
body('password')
|
||||
.isLength({min: 4}).withMessage('حداقل 4 کاراکتر')
|
||||
.isLength({min: 4}).withMessage(v_m['fa'].min_char.min4)
|
||||
.custom((value, {req}) => {
|
||||
return value === req.body.password_confirmation
|
||||
}).withMessage('پسورد ها یکی نیست.')
|
||||
if (value === req.body.password_confirmation) return true
|
||||
else return Promise.reject(v_m['fa'].response.passwords_not_match)
|
||||
})
|
||||
],
|
||||
(req, res) => {
|
||||
const errors = validationResult(req)
|
||||
@@ -34,7 +36,6 @@ module.exports.register = [
|
||||
const data = {}
|
||||
data.name = req.body.name
|
||||
data.username = req.body.username
|
||||
data.scope = 'admin'
|
||||
data.created_at = dateformat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
|
||||
|
||||
bcrypt.genSalt(10, (err, salt) => {
|
||||
@@ -45,7 +46,7 @@ module.exports.register = [
|
||||
const admin = new Admin(data)
|
||||
admin.save(err => {
|
||||
if (err) console.log(err)
|
||||
return res.json({message: 'Admin added.'})
|
||||
return res.json({message: v_m['fa'].response.success_save})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -57,20 +58,26 @@ module.exports.register = [
|
||||
module.exports.login = [
|
||||
[
|
||||
body('username')
|
||||
.isLength({min: 4}).withMessage('حداقل 4 کاراکتر')
|
||||
.isLength({min: 4}).withMessage(v_m['fa'].min_char.min4)
|
||||
.bail()
|
||||
.if((value, {req}) => {
|
||||
return req.body.password && req.body.password.length >= 4
|
||||
})
|
||||
.custom((value, {req}) => {
|
||||
return Admin.findOne({username: value})
|
||||
.then(admin => {
|
||||
if (!admin) return Promise.reject('ادمینی با این نام وجود ندارد.')
|
||||
if (!admin) return Promise.reject(v_m['fa'].not_found.admin_id)
|
||||
else return true
|
||||
})
|
||||
}),
|
||||
|
||||
body('password')
|
||||
.isLength({min: 4}).withMessage('حداقل 4 کاراکتر'),
|
||||
.notEmpty().withMessage(v_m['fa'].required.password)
|
||||
.bail()
|
||||
.isLength({min: 4}).withMessage(v_m['fa'].min_char.min4),
|
||||
|
||||
body('remember_me')
|
||||
.exists().withMessage('پارامتر remember_me الزامی است.')
|
||||
.exists().withMessage(v_m['fa'].required.remember_me)
|
||||
.bail()
|
||||
.isBoolean().withMessage('مقدار باید از جنس Boolean باشد.')
|
||||
],
|
||||
@@ -82,18 +89,17 @@ module.exports.login = [
|
||||
if (err) console.log(err)
|
||||
bcrypt.compare(req.body.password, user.password, (err, isMatch) => {
|
||||
if (err) console.log(err)
|
||||
if (!isMatch) return res.status(422).json({validation: {password: {msg: 'پسورد اشتباه است.'}}})
|
||||
if (!isMatch) return res.status(422).json({validation: {password: {msg: v_m['fa'].not_found.password}}})
|
||||
|
||||
let token
|
||||
if (req.body.remember_me) token = jwt.sign({_id: user._id}, config.secretKey)
|
||||
else token = jwt.sign({_id: user._id}, config.secretKey, {expiresIn: '1h'})
|
||||
|
||||
user.token = token
|
||||
user.markModified('token')
|
||||
user.save(err => {
|
||||
if (err) console.log(err)
|
||||
return res.json({token: token})
|
||||
})
|
||||
return res.json({token: token})
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -106,11 +112,11 @@ module.exports.logout = [
|
||||
if (token) {
|
||||
Admin.findOneAndUpdate({token: token}, {token: null}, (err, oldData) => {
|
||||
if (err) console.log(err)
|
||||
if (oldData) return res.json({message: 'You are logged out.'})
|
||||
return res.status(401).json({message: 'Your not logged in'})
|
||||
if (oldData) return res.json({message: v_m['fa'].response.logged_out})
|
||||
return res.status(401).json({message: v_m['fa'].response.not_logged_in})
|
||||
})
|
||||
} else {
|
||||
return res.status(401).json({message: 'Your not logged in'})
|
||||
return res.status(401).json({message: v_m['fa'].response.not_logged_in})
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -2,56 +2,28 @@ const BlogCategory = require('../models/blog/BlogCategory')
|
||||
const BlogPost = require('../models/blog/BlogPost')
|
||||
const dateformat = require('dateformat')
|
||||
const {body, validationResult} = require('express-validator')
|
||||
|
||||
const v_m = require('../validation_messages')
|
||||
|
||||
module.exports.create = [
|
||||
[
|
||||
body('fa_name')
|
||||
.notEmpty().withMessage('نام نباید خالی باشد.')
|
||||
.notEmpty().withMessage(v_m['fa'].required.title)
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return BlogCategory.findOne({'blogCategory_details.fa.name': value}).then(category => {
|
||||
if (category) return Promise.reject('این نام از قبل وجود دارد.')
|
||||
if (category) return Promise.reject(v_m['fa'].duplicated.title)
|
||||
return true
|
||||
})
|
||||
}),
|
||||
body('en_name')
|
||||
.notEmpty().withMessage('نام نباید خالی باشد.')
|
||||
.notEmpty().withMessage(v_m['fa'].required.title)
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return BlogCategory.findOne({'blogCategory_details.en.name': value}).then(category => {
|
||||
if (category) return Promise.reject('این نام از قبل وجود دارد.')
|
||||
return true
|
||||
})
|
||||
}),
|
||||
body('de_name')
|
||||
.notEmpty().withMessage('نام نباید خالی باشد.')
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return BlogCategory.findOne({'blogCategory_details.de.name': value}).then(category => {
|
||||
if (category) return Promise.reject('این نام از قبل وجود دارد.')
|
||||
return true
|
||||
})
|
||||
}),
|
||||
body('tr_name')
|
||||
.notEmpty().withMessage('نام نباید خالی باشد.')
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return BlogCategory.findOne({'blogCategory_details.tr.name': value}).then(category => {
|
||||
if (category) return Promise.reject('این نام از قبل وجود دارد.')
|
||||
return true
|
||||
})
|
||||
}),
|
||||
body('it_name')
|
||||
.notEmpty().withMessage('نام نباید خالی باشد.')
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return BlogCategory.findOne({'blogCategory_details.it.name': value}).then(category => {
|
||||
if (category) return Promise.reject('این نام از قبل وجود دارد.')
|
||||
if (category) return Promise.reject(v_m['fa'].duplicated.title)
|
||||
return true
|
||||
})
|
||||
})
|
||||
|
||||
],
|
||||
(req, res) => {
|
||||
const errors = validationResult(req)
|
||||
@@ -64,22 +36,13 @@ module.exports.create = [
|
||||
},
|
||||
en: {
|
||||
name: req.body.en_name
|
||||
},
|
||||
de: {
|
||||
name: req.body.de_name
|
||||
},
|
||||
tr: {
|
||||
name: req.body.tr_name
|
||||
},
|
||||
it: {
|
||||
name: req.body.it_name
|
||||
}
|
||||
},
|
||||
created_at: dateformat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
|
||||
})
|
||||
blogCategory.save(err => {
|
||||
if (err) console.log(err)
|
||||
return res.json({message: 'دسته بندی اضافه شد.'})
|
||||
return res.json({message: v_m['fa'].response.success_save})
|
||||
})
|
||||
}
|
||||
]
|
||||
@@ -108,47 +71,20 @@ module.exports.getOne = [
|
||||
module.exports.update = [
|
||||
[
|
||||
body('fa_name')
|
||||
.notEmpty().withMessage('نام نباید خالی باشد.')
|
||||
.notEmpty().withMessage(v_m['fa'].required.title)
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return BlogCategory.findOne({'blogCategory_details.fa.name': value}).then(category => {
|
||||
if (category && category._id.toString() !== req.params.id) return Promise.reject('این نام از قبل وجود دارد.')
|
||||
if (category && category._id.toString() !== req.params.id) return Promise.reject(v_m['fa'].duplicated.title)
|
||||
return true
|
||||
})
|
||||
}),
|
||||
body('en_name')
|
||||
.notEmpty().withMessage('نام نباید خالی باشد.')
|
||||
.notEmpty().withMessage(v_m['fa'].required.title)
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return BlogCategory.findOne({'blogCategory_details.en.name': value}).then(category => {
|
||||
if (category && category._id.toString() !== req.params.id) return Promise.reject('این نام از قبل وجود دارد.')
|
||||
return true
|
||||
})
|
||||
}),
|
||||
body('de_name')
|
||||
.notEmpty().withMessage('نام نباید خالی باشد.')
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return BlogCategory.findOne({'blogCategory_details.de.name': value}).then(category => {
|
||||
if (category && category._id.toString() !== req.params.id) return Promise.reject('این نام از قبل وجود دارد.')
|
||||
return true
|
||||
})
|
||||
}),
|
||||
body('tr_name')
|
||||
.notEmpty().withMessage('نام نباید خالی باشد.')
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return BlogCategory.findOne({'blogCategory_details.tr.name': value}).then(category => {
|
||||
if (category && category._id.toString() !== req.params.id) return Promise.reject('این نام از قبل وجود دارد.')
|
||||
return true
|
||||
})
|
||||
}),
|
||||
body('it_name')
|
||||
.notEmpty().withMessage('نام نباید خالی باشد.')
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return BlogCategory.findOne({'blogCategory_details.it.name': value}).then(category => {
|
||||
if (category && category._id.toString() !== req.params.id) return Promise.reject('این نام از قبل وجود دارد.')
|
||||
if (category && category._id.toString() !== req.params.id) return Promise.reject(v_m['fa'].duplicated.title)
|
||||
return true
|
||||
})
|
||||
})
|
||||
@@ -164,22 +100,13 @@ module.exports.update = [
|
||||
},
|
||||
en: {
|
||||
name: req.body.en_name
|
||||
},
|
||||
de: {
|
||||
name: req.body.de_name
|
||||
},
|
||||
tr: {
|
||||
name: req.body.tr_name
|
||||
},
|
||||
it: {
|
||||
name: req.body.it_name
|
||||
}
|
||||
},
|
||||
updated_at: dateformat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
|
||||
}
|
||||
BlogCategory.findByIdAndUpdate(req.params.id, data, (err, oldData) => {
|
||||
if (err) console.log(err)
|
||||
return res.json({message: 'دسته بندی بروزرسانی شد.'})
|
||||
return res.json({message: v_m['fa'].response.success_save})
|
||||
})
|
||||
}
|
||||
]
|
||||
@@ -187,12 +114,12 @@ module.exports.update = [
|
||||
|
||||
module.exports.delete = [
|
||||
(req, res) => {
|
||||
BlogPost.find({category: req.params.id}, (err, categories) => {
|
||||
BlogPost.find({category: req.params.id}, (err, posts) => {
|
||||
if (err) console.log(err)
|
||||
if (!categories.length) {
|
||||
if (!posts.length) {
|
||||
BlogCategory.findByIdAndDelete(req.params.id, (err) => {
|
||||
if (err) return res.status(404).json({message: err})
|
||||
return res.json({message: 'دسته بندی حذف شد.'})
|
||||
return res.json({message: v_m['fa'].response.success_save})
|
||||
})
|
||||
} else {
|
||||
return res.status(500).json({message: 'نمیتوان دسته بندی هایی که دارای پست هستند را پاک کرد.'})
|
||||
|
||||
@@ -3,102 +3,48 @@ const dateformat = require('dateformat')
|
||||
const {body, validationResult} = require('express-validator')
|
||||
const fs = require('fs')
|
||||
const jimp = require('jimp')
|
||||
const v_m = require('../validation_messages')
|
||||
|
||||
module.exports.create = [
|
||||
[
|
||||
// title
|
||||
body('fa_title')
|
||||
.notEmpty().withMessage('عنوان نباید خالی باشد.')
|
||||
.notEmpty().withMessage(v_m['fa'].required.title)
|
||||
.bail()
|
||||
.isLength({max: 60}).withMessage('حداکثر 60 کاراکتر مجاز است.')
|
||||
.isLength({max: 120}).withMessage(v_m['fa'].max_char.max120)
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return BlogPost.findOne({'post_details.fa.title': value}).then(post => {
|
||||
if (post) return Promise.reject('عنوان تکراری است.')
|
||||
if (post) return Promise.reject(v_m['fa'].duplicated.title)
|
||||
return true
|
||||
})
|
||||
}),
|
||||
body('en_title')
|
||||
.notEmpty().withMessage('عنوان نباید خالی باشد.')
|
||||
.notEmpty().withMessage(v_m['fa'].required.title)
|
||||
.bail()
|
||||
.isLength({max: 60}).withMessage('حداکثر 60 کاراکتر مجاز است.')
|
||||
.isLength({max: 120}).withMessage(v_m['fa'].max_char.max120)
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return BlogPost.findOne({'post_details.en.title': value}).then(post => {
|
||||
if (post) return Promise.reject('عنوان تکراری است.')
|
||||
return true
|
||||
})
|
||||
}),
|
||||
body('de_title')
|
||||
.notEmpty().withMessage('عنوان نباید خالی باشد.')
|
||||
.bail()
|
||||
.isLength({max: 60}).withMessage('حداکثر 60 کاراکتر مجاز است.')
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return BlogPost.findOne({'post_details.de.title': value}).then(post => {
|
||||
if (post) return Promise.reject('عنوان تکراری است.')
|
||||
return true
|
||||
})
|
||||
}),
|
||||
body('tr_title')
|
||||
.notEmpty().withMessage('عنوان نباید خالی باشد.')
|
||||
.bail()
|
||||
.isLength({max: 60}).withMessage('حداکثر 60 کاراکتر مجاز است.')
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return BlogPost.findOne({'post_details.tr.title': value}).then(post => {
|
||||
if (post) return Promise.reject('عنوان تکراری است.')
|
||||
return true
|
||||
})
|
||||
}),
|
||||
body('it_title')
|
||||
.notEmpty().withMessage('عنوان نباید خالی باشد.')
|
||||
.bail()
|
||||
.isLength({max: 60}).withMessage('حداکثر 60 کاراکتر مجاز است.')
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return BlogPost.findOne({'post_details.it.title': value}).then(post => {
|
||||
if (post) return Promise.reject('عنوان تکراری است.')
|
||||
if (post) return Promise.reject(v_m['fa'].duplicated.title)
|
||||
return true
|
||||
})
|
||||
}),
|
||||
|
||||
// description
|
||||
body('fa_description')
|
||||
.notEmpty().withMessage('توضیحات نباید خالی باشد.'),
|
||||
.notEmpty().withMessage(v_m['fa'].required.description),
|
||||
body('en_description')
|
||||
.notEmpty().withMessage('توضیحات نباید خالی باشد.'),
|
||||
body('de_description')
|
||||
.notEmpty().withMessage('توضیحات نباید خالی باشد.'),
|
||||
body('tr_description')
|
||||
.notEmpty().withMessage('توضیحات نباید خالی باشد.'),
|
||||
body('it_description')
|
||||
.notEmpty().withMessage('توضیحات نباید خالی باشد.'),
|
||||
.notEmpty().withMessage(v_m['fa'].required.description),
|
||||
|
||||
// short description
|
||||
body('fa_short_description')
|
||||
.notEmpty().withMessage('توضیح کوتاه نباید خالی باشد.')
|
||||
.bail()
|
||||
.isLength({max: 120}).withMessage('حداکثر 120 کاراکتر مجاز است.'),
|
||||
.notEmpty().withMessage(v_m['fa'].required.description),
|
||||
body('en_short_description')
|
||||
.notEmpty().withMessage('توضیح کوتاه نباید خالی باشد.')
|
||||
.bail()
|
||||
.isLength({max: 120}).withMessage('حداکثر 120 کاراکتر مجاز است.'),
|
||||
body('de_short_description')
|
||||
.notEmpty().withMessage('توضیح کوتاه نباید خالی باشد.')
|
||||
.bail()
|
||||
.isLength({max: 120}).withMessage('حداکثر 120 کاراکتر مجاز است.'),
|
||||
body('tr_short_description')
|
||||
.notEmpty().withMessage('توضیح کوتاه نباید خالی باشد.')
|
||||
.bail()
|
||||
.isLength({max: 120}).withMessage('حداکثر 120 کاراکتر مجاز است.'),
|
||||
body('it_short_description')
|
||||
.notEmpty().withMessage('توضیح کوتاه نباید خالی باشد.')
|
||||
.bail()
|
||||
.isLength({max: 120}).withMessage('حداکثر 120 کاراکتر مجاز است.'),
|
||||
.notEmpty().withMessage(v_m['fa'].required.description),
|
||||
|
||||
body('category')
|
||||
.notEmpty().withMessage('دسته بندی را انتخاب کنید.')
|
||||
.notEmpty().withMessage(v_m['fa'].required.category)
|
||||
],
|
||||
(req, res) => {
|
||||
const errors = validationResult(req)
|
||||
@@ -107,25 +53,24 @@ module.exports.create = [
|
||||
let cover
|
||||
let coverName
|
||||
|
||||
// 305 X 170
|
||||
// 1370 x 556
|
||||
// 460 X 320
|
||||
// 1920 x 720
|
||||
|
||||
if (req.files && req.files.cover) {
|
||||
cover = req.files.cover
|
||||
coverName = 'blog_' + Date.now() + '.' + cover.mimetype.split('/')[1]
|
||||
|
||||
if (cover.size / 1024 > 500) return res.status(422).json({validation: {cover: {msg: 'حجم عکس نباید بیشتر از 500 کیلوبایت باشد.'}}})
|
||||
} else {
|
||||
return res.status(422).json({validation: {cover: {msg: 'کاور اجباری است.'}}})
|
||||
return res.status(422).json({validation: {cover: {msg: v_m['fa'].required.cover}}})
|
||||
}
|
||||
|
||||
jimp.read(cover.data)
|
||||
.then(img => {
|
||||
img
|
||||
.cover(1370, 688)
|
||||
.cover(1920, 720)
|
||||
.quality(70)
|
||||
.write(`./static/uploads/images/blog/${coverName}`)
|
||||
.resize(305, jimp.AUTO)
|
||||
.cover(305, 170)
|
||||
.resize(460, jimp.AUTO)
|
||||
.cover(460, 320)
|
||||
.write(`./static/uploads/images/blog/thumb_${coverName}`)
|
||||
})
|
||||
|
||||
@@ -140,21 +85,6 @@ module.exports.create = [
|
||||
title: req.body.en_title,
|
||||
description: req.body.en_description,
|
||||
short_description: req.body.en_short_description
|
||||
},
|
||||
de: {
|
||||
title: req.body.de_title,
|
||||
description: req.body.de_description,
|
||||
short_description: req.body.de_short_description
|
||||
},
|
||||
tr: {
|
||||
title: req.body.tr_title,
|
||||
description: req.body.tr_description,
|
||||
short_description: req.body.tr_short_description
|
||||
},
|
||||
it: {
|
||||
title: req.body.it_title,
|
||||
description: req.body.it_description,
|
||||
short_description: req.body.it_short_description
|
||||
}
|
||||
},
|
||||
cover: coverName,
|
||||
@@ -166,7 +96,7 @@ module.exports.create = [
|
||||
const post = new BlogPost(data)
|
||||
post.save(err => {
|
||||
if (err) console.log(err)
|
||||
return res.json({message: 'پست با موفقیت اضافه شد.'})
|
||||
return res.json({message: v_m['fa'].response.success_save})
|
||||
})
|
||||
}
|
||||
]
|
||||
@@ -196,97 +126,44 @@ module.exports.update = [
|
||||
[
|
||||
// title
|
||||
body('fa_title')
|
||||
.notEmpty().withMessage('عنوان نباید خالی باشد.')
|
||||
.notEmpty().withMessage(v_m['fa'].required.title)
|
||||
.bail()
|
||||
.isLength({max: 60}).withMessage('حداکثر 60 کاراکتر مجاز است.')
|
||||
.isLength({max: 120}).withMessage(v_m['fa'].max_char.max120)
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return BlogPost.findOne({'post_details.fa.title': value}).then(post => {
|
||||
if (post && post._id.toString() !== req.params.id) return Promise.reject('عنوان تکراری است.')
|
||||
if (post && post._id.toString() !== req.params.id) return Promise.reject(v_m['fa'].duplicated.title)
|
||||
return true
|
||||
})
|
||||
}),
|
||||
body('en_title')
|
||||
.notEmpty().withMessage('عنوان نباید خالی باشد.')
|
||||
.notEmpty().withMessage(v_m['fa'].required.title)
|
||||
.bail()
|
||||
.isLength({max: 60}).withMessage('حداکثر 60 کاراکتر مجاز است.')
|
||||
.isLength({max: 120}).withMessage(v_m['fa'].max_char.max120)
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return BlogPost.findOne({'post_details.en.title': value}).then(post => {
|
||||
if (post && post._id.toString() !== req.params.id) return Promise.reject('عنوان تکراری است.')
|
||||
return true
|
||||
})
|
||||
}),
|
||||
body('de_title')
|
||||
.notEmpty().withMessage('عنوان نباید خالی باشد.')
|
||||
.bail()
|
||||
.isLength({max: 60}).withMessage('حداکثر 60 کاراکتر مجاز است.')
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return BlogPost.findOne({'post_details.de.title': value}).then(post => {
|
||||
if (post && post._id.toString() !== req.params.id) return Promise.reject('عنوان تکراری است.')
|
||||
return true
|
||||
})
|
||||
}),
|
||||
body('tr_title')
|
||||
.notEmpty().withMessage('عنوان نباید خالی باشد.')
|
||||
.bail()
|
||||
.isLength({max: 60}).withMessage('حداکثر 60 کاراکتر مجاز است.')
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return BlogPost.findOne({'post_details.tr.title': value}).then(post => {
|
||||
if (post && post._id.toString() !== req.params.id) return Promise.reject('عنوان تکراری است.')
|
||||
return true
|
||||
})
|
||||
}),
|
||||
body('it_title')
|
||||
.notEmpty().withMessage('عنوان نباید خالی باشد.')
|
||||
.bail()
|
||||
.isLength({max: 60}).withMessage('حداکثر 60 کاراکتر مجاز است.')
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return BlogPost.findOne({'post_details.it.title': value}).then(post => {
|
||||
if (post && post._id.toString() !== req.params.id) return Promise.reject('عنوان تکراری است.')
|
||||
if (post && post._id.toString() !== req.params.id) return Promise.reject(v_m['fa'].duplicated.title)
|
||||
return true
|
||||
})
|
||||
}),
|
||||
|
||||
|
||||
// description
|
||||
body('fa_description')
|
||||
.notEmpty().withMessage('توضیحات نباید خالی باشد.'),
|
||||
.notEmpty().withMessage(v_m['fa'].required.description),
|
||||
body('en_description')
|
||||
.notEmpty().withMessage('توضیحات نباید خالی باشد.'),
|
||||
body('de_description')
|
||||
.notEmpty().withMessage('توضیحات نباید خالی باشد.'),
|
||||
body('tr_description')
|
||||
.notEmpty().withMessage('توضیحات نباید خالی باشد.'),
|
||||
body('it_description')
|
||||
.notEmpty().withMessage('توضیحات نباید خالی باشد.'),
|
||||
.notEmpty().withMessage(v_m['fa'].required.description),
|
||||
|
||||
// short description
|
||||
body('fa_short_description')
|
||||
.notEmpty().withMessage('توضیح کوتاه نباید خالی باشد.')
|
||||
.bail()
|
||||
.isLength({max: 120}).withMessage('حداکثر 120 کاراکتر مجاز است.'),
|
||||
.notEmpty().withMessage(v_m['fa'].required.description),
|
||||
body('en_short_description')
|
||||
.notEmpty().withMessage('توضیح کوتاه نباید خالی باشد.')
|
||||
.bail()
|
||||
.isLength({max: 120}).withMessage('حداکثر 120 کاراکتر مجاز است.'),
|
||||
body('de_short_description')
|
||||
.notEmpty().withMessage('توضیح کوتاه نباید خالی باشد.')
|
||||
.bail()
|
||||
.isLength({max: 120}).withMessage('حداکثر 120 کاراکتر مجاز است.'),
|
||||
body('tr_short_description')
|
||||
.notEmpty().withMessage('توضیح کوتاه نباید خالی باشد.')
|
||||
.bail()
|
||||
.isLength({max: 120}).withMessage('حداکثر 120 کاراکتر مجاز است.'),
|
||||
body('it_short_description')
|
||||
.notEmpty().withMessage('توضیح کوتاه نباید خالی باشد.')
|
||||
.bail()
|
||||
.isLength({max: 120}).withMessage('حداکثر 120 کاراکتر مجاز است.'),
|
||||
.notEmpty().withMessage(v_m['fa'].required.description),
|
||||
|
||||
|
||||
body('category')
|
||||
.notEmpty().withMessage('دسته بندی را انتخاب کنید.')
|
||||
.notEmpty().withMessage(v_m['fa'].required.category)
|
||||
],
|
||||
(req, res) => {
|
||||
const errors = validationResult(req)
|
||||
@@ -304,21 +181,6 @@ module.exports.update = [
|
||||
title: req.body.en_title,
|
||||
description: req.body.en_description,
|
||||
short_description: req.body.en_short_description
|
||||
},
|
||||
de: {
|
||||
title: req.body.de_title,
|
||||
description: req.body.de_description,
|
||||
short_description: req.body.de_short_description
|
||||
},
|
||||
tr: {
|
||||
title: req.body.tr_title,
|
||||
description: req.body.tr_description,
|
||||
short_description: req.body.tr_short_description
|
||||
},
|
||||
it: {
|
||||
title: req.body.it_title,
|
||||
description: req.body.it_description,
|
||||
short_description: req.body.it_short_description
|
||||
}
|
||||
},
|
||||
published: req.body.published,
|
||||
@@ -326,8 +188,9 @@ module.exports.update = [
|
||||
updated_at: dateformat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
|
||||
}
|
||||
|
||||
// 305 X 170
|
||||
// 1370 x 556
|
||||
// 460 X 320
|
||||
// 1920 x 720
|
||||
|
||||
let cover
|
||||
let coverName
|
||||
|
||||
@@ -335,28 +198,29 @@ module.exports.update = [
|
||||
cover = req.files.cover
|
||||
coverName = 'blog_' + Date.now() + '.' + cover.mimetype.split('/')[1]
|
||||
|
||||
if (cover.size / 1024 > 500) return res.status(422).json({validation: {cover: {msg: 'حجم عکس نباید بیشتر از 500 کیلوبایت باشد.'}}})
|
||||
data.cover = coverName
|
||||
jimp.read(cover.data)
|
||||
.then(img => {
|
||||
img
|
||||
.cover(1370, 688)
|
||||
.cover(1920, 720)
|
||||
.write(`./static/uploads/images/blog/${coverName}`)
|
||||
.resize(305, jimp.AUTO)
|
||||
.cover(305, 170)
|
||||
.resize(460, jimp.AUTO)
|
||||
.cover(460, 320)
|
||||
.write(`./static/uploads/images/blog/thumb_${coverName}`)
|
||||
})
|
||||
}
|
||||
|
||||
BlogPost.findByIdAndUpdate(req.params.id, data, (err, oldData) => {
|
||||
if (err) console.log(err)
|
||||
if (cover && cover.data) fs.unlink(`./static/${oldData.cover}`, err => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
if (cover && cover.data) fs.unlink(`./static/${oldData.thumb}`, err => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
return res.json({message: 'پست با موفقیت بروزرسانی شد.'})
|
||||
if (cover && cover.data) {
|
||||
fs.unlink(`./static/${oldData.cover}`, err => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
fs.unlink(`./static/${oldData.thumb}`, err => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
}
|
||||
return res.json({message: v_m['fa'].response.success_save})
|
||||
})
|
||||
}
|
||||
]
|
||||
@@ -372,7 +236,7 @@ module.exports.delete = [
|
||||
fs.unlink(`./static/${post.thumb}`, err => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
return res.json({message: 'پست حذف شد.'})
|
||||
return res.json({message: v_m['fa'].response.success_remove})
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
const Broadcast = require('../models/Broadcast')
|
||||
const {body, validationResult} = require('express-validator')
|
||||
const dateformat = require('dateformat')
|
||||
|
||||
|
||||
module.exports.create = [
|
||||
[
|
||||
body('title')
|
||||
.isLength({min: 2}).withMessage('حداقل 2 کاراکتر'),
|
||||
|
||||
body('message')
|
||||
.isLength({min: 10}).withMessage('حداقل 10 کاراکتر'),
|
||||
|
||||
body('locale')
|
||||
.notEmpty().withMessage('زبان پیام را انتخاب کنید')
|
||||
],
|
||||
(req, res) => {
|
||||
const errors = validationResult(req)
|
||||
if (!errors.isEmpty()) return res.status(422).json({validation: errors.mapped()})
|
||||
|
||||
const data = {
|
||||
title: req.body.title,
|
||||
message: req.body.message,
|
||||
admin_id: req.body.admin_id,
|
||||
locale: req.body.locale,
|
||||
created_at: dateformat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
|
||||
}
|
||||
const broadcast = new Broadcast(data)
|
||||
broadcast.save((err, data) => {
|
||||
if (err) console.log(err)
|
||||
return res.json(data)
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
module.exports.getAll = [
|
||||
(req, res) => {
|
||||
Broadcast.find({})
|
||||
.then(messages => {
|
||||
return res.json(messages)
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
module.exports.getOne = [
|
||||
(req, res) => {
|
||||
Broadcast.findById(req.params.id)
|
||||
.then(message => {
|
||||
if (!message.read.includes(req.body.user_id)) {
|
||||
message.read.push(req.body.user_id)
|
||||
message.save(err => {
|
||||
if (err) console.log(err)
|
||||
return res.json(message)
|
||||
})
|
||||
} else {
|
||||
return res.json(message)
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
module.exports.delete = [
|
||||
(req, res) => {
|
||||
Broadcast.findByIdAndDelete(req.params.id)
|
||||
.then(message => {
|
||||
return res.json({message: 'Message deleted.'})
|
||||
})
|
||||
.catch(err => {
|
||||
return res.status(404).json(err)
|
||||
})
|
||||
}
|
||||
]
|
||||
@@ -49,6 +49,12 @@ module.exports.create = [
|
||||
return v_m[req.body.locale].format.email
|
||||
}),
|
||||
|
||||
body('reason')
|
||||
.custom((value, {req}) => {
|
||||
if (!value) return Promise.reject(v_m[req.body.locale].required.reason)
|
||||
else return true
|
||||
}),
|
||||
|
||||
body('message')
|
||||
.isLength({min: 50})
|
||||
.withMessage((value, {req}) => {
|
||||
@@ -66,7 +72,7 @@ module.exports.create = [
|
||||
phone_number: req.body.phone_number,
|
||||
email: req.body.email,
|
||||
message: req.body.message,
|
||||
user_id: req.body.user_id,
|
||||
reason: req.body.reason,
|
||||
created_at: dateformat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
|
||||
}
|
||||
const message = new ContactPageMessage(data)
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
const Reason = require('../models/ContactUsReason')
|
||||
const {body, validationResult} = require('express-validator')
|
||||
const dateformat = require('dateformat')
|
||||
const v_m = require('../validation_messages')
|
||||
|
||||
|
||||
module.exports.create = [
|
||||
[
|
||||
body('fa_reason')
|
||||
.notEmpty().withMessage(v_m['fa'].required.title),
|
||||
|
||||
body('en_reason')
|
||||
.notEmpty().withMessage(v_m['fa'].required.title)
|
||||
],
|
||||
(req, res) => {
|
||||
const errors = validationResult(req)
|
||||
if (!errors.isEmpty()) return res.status(422).json({validation: errors.mapped()})
|
||||
|
||||
const data = {
|
||||
reason_details: {
|
||||
fa: {
|
||||
reason: req.body.fa_reason
|
||||
},
|
||||
en: {
|
||||
reason: req.body.en_reason
|
||||
}
|
||||
},
|
||||
created_at: dateformat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
|
||||
}
|
||||
|
||||
const reason = new Reason(data)
|
||||
reason.save(err => {
|
||||
if (err) console.log(err)
|
||||
Reason.find({}, (err2, data) => {
|
||||
if (err2) console.log(err2)
|
||||
return res.json(data)
|
||||
})
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
module.exports.getAll = [
|
||||
(req, res) => {
|
||||
Reason.find({}, (err, data) => {
|
||||
if (err) console.log(err)
|
||||
return res.json(data)
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
module.exports.delete = [
|
||||
(req, res) => {
|
||||
Reason.findByIdAndDelete(req.params.id, (err, reason) => {
|
||||
if (err) console.log(err)
|
||||
return res.json({message: v_m['fa'].response.success_remove})
|
||||
})
|
||||
}
|
||||
]
|
||||
@@ -1,89 +0,0 @@
|
||||
const Gallery = require('../models/Gallery')
|
||||
const jimp = require('jimp')
|
||||
const fs = require('fs')
|
||||
const dateFormat = require('dateformat')
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////// create image
|
||||
module.exports.create = [
|
||||
(req, res) => {
|
||||
let file
|
||||
let fileName
|
||||
|
||||
////////////// validate image upload
|
||||
if (req.files) {
|
||||
file = req.files.image
|
||||
fileName = 'gallery_' + Date.now() + '.' + file.mimetype.split('/')[1]
|
||||
jimp.read(file.data)
|
||||
.then(img => {
|
||||
img
|
||||
.cover(940, 620, jimp.HORIZONTAL_ALIGN_CENTER | jimp.VERTICAL_ALIGN_MIDDLE)
|
||||
.write(`./static/uploads/images/gallery/${fileName}`, (err, img) => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
.resize(335, jimp.AUTO)
|
||||
.write(`./static/uploads/images/gallery/thumb/thumb_${fileName}`, (err, img) => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
|
||||
let gallery = new Gallery({
|
||||
image: fileName,
|
||||
created_at: dateFormat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
|
||||
})
|
||||
gallery.save((err, image) => {
|
||||
if (err) return res.status(500).json(err)
|
||||
Gallery.find({})
|
||||
.then(images => {
|
||||
return res.json(images)
|
||||
})
|
||||
.catch(err => {
|
||||
return res.status(500).json(err)
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
|
||||
} else {
|
||||
return res.status(422).json({validation: {image: {msg: 'عکس اجباری است'}}})
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////// get all images
|
||||
module.exports.getAll = [
|
||||
(req, res) => {
|
||||
Gallery.find({}, (err, images) => {
|
||||
if (err) return res.json({errors: err})
|
||||
return res.json(images)
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////// get one image
|
||||
module.exports.getOne = [
|
||||
(req, res) => {
|
||||
Gallery.findById(req.params.id, (err, image) => {
|
||||
if (err) return res.json({errors: err})
|
||||
return res.json(image)
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////// delete image
|
||||
module.exports.delete = [
|
||||
(req, res) => {
|
||||
Gallery.findByIdAndRemove(req.params.id, (err, data) => {
|
||||
if (err) return res.json({error: err})
|
||||
fs.unlink(`./static/${data.image}`, err => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
fs.unlink(`./static/${data.thumb}`, err => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
return res.json({message: 'تصویر حذف شد'})
|
||||
})
|
||||
}
|
||||
]
|
||||
@@ -1,36 +0,0 @@
|
||||
const locales = [
|
||||
{
|
||||
name: 'فارسی',
|
||||
value: 'fa',
|
||||
currency: 'ريال'
|
||||
},
|
||||
{
|
||||
name: 'انگلیسی',
|
||||
value: 'en',
|
||||
currency: 'USD'
|
||||
},
|
||||
{
|
||||
name: 'آلمانی',
|
||||
value: 'de',
|
||||
currency: 'EUR'
|
||||
},
|
||||
{
|
||||
name: 'ترکی',
|
||||
value: 'tr',
|
||||
currency: 'TL'
|
||||
},
|
||||
{
|
||||
name: 'ایتالیایی',
|
||||
value: 'it',
|
||||
currency: 'EUR'
|
||||
}
|
||||
]
|
||||
|
||||
module.exports.locales = locales
|
||||
|
||||
module.exports.get = [
|
||||
(req, res) => {
|
||||
return res.json(locales)
|
||||
}
|
||||
]
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
const MainCatalog = require('../models/MainCatalog')
|
||||
const dateformat = require('dateformat')
|
||||
const v_m = require('../validation_messages')
|
||||
const fs = require('fs')
|
||||
|
||||
module.exports.create = [
|
||||
(req, res) => {
|
||||
if (!req.files || !req.files.pdf) return res.status(422).json({validation: {pdf: {msg: v_m['fa'].required.file}}})
|
||||
if (req.files.pdf.mimetype.split('/')[1] !== 'pdf') return res.status(422).json({validation: {pdf: {msg: v_m['fa'].file_types.pdf}}})
|
||||
|
||||
|
||||
MainCatalog.find({}, (err, catalogs) => {
|
||||
if (catalogs.length) {
|
||||
let firstFile = catalogs[0]
|
||||
fs.unlink(`./static/${firstFile.file}`, err => {
|
||||
if (err) console.log(err)
|
||||
firstFile.file = req.files.pdf.name
|
||||
firstFile.created_at = dateformat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
|
||||
firstFile.save((err1, data) => {
|
||||
if (err1) console.log(err1)
|
||||
req.files.pdf.mv(`./static/uploads/pdf/${req.files.pdf.name}`)
|
||||
return res.json(firstFile)
|
||||
})
|
||||
|
||||
})
|
||||
} else {
|
||||
new MainCatalog({
|
||||
file: req.files.pdf.name,
|
||||
created_at: dateformat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
|
||||
}).save((err, data) => {
|
||||
if (err) console.log(err)
|
||||
req.files.pdf.mv(`./static/uploads/pdf/${req.files.pdf.name}`)
|
||||
return res.json(data)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
module.exports.get = [
|
||||
(req, res) => {
|
||||
MainCatalog.find({}, (err, catalog) => {
|
||||
if (err) console.log(err)
|
||||
if (catalog.length) return res.json(catalog[0])
|
||||
else return res.json({})
|
||||
})
|
||||
}
|
||||
]
|
||||
@@ -1,298 +0,0 @@
|
||||
const Cart_Item = require('../models/user/Cart_item')
|
||||
const Order = require('../models/user/Order')
|
||||
const User = require('../models/user/User')
|
||||
const localeController = require('./localeController')
|
||||
const Product = require('../models/product/Product')
|
||||
const {body, validationResult} = require('express-validator')
|
||||
const dateformat = require('dateformat')
|
||||
const v_m = require('../validation_messages')
|
||||
|
||||
////////////////////////////////////// cart
|
||||
module.exports.addToCart = [
|
||||
[
|
||||
body('user_id')
|
||||
.custom((value, {req}) => {
|
||||
return User.findById(value)
|
||||
.then(user => {
|
||||
if (user) return true
|
||||
})
|
||||
.catch(err => {
|
||||
return Promise.reject(v_m[req.body.locale].not_found.user_id)
|
||||
})
|
||||
}),
|
||||
|
||||
body('product_id')
|
||||
.custom((value, {req}) => {
|
||||
return Product.findById(value)
|
||||
.then(product => {
|
||||
if (product) return true
|
||||
})
|
||||
.catch(err => {
|
||||
return Promise.reject(v_m[req.body.locale].not_found.item_id)
|
||||
})
|
||||
}),
|
||||
body('quantity')
|
||||
.notEmpty()
|
||||
.withMessage((value, {req}) => {
|
||||
return v_m[req.body.locale].required.quantity
|
||||
})
|
||||
.bail()
|
||||
.isNumeric()
|
||||
.withMessage((value, {req}) => {
|
||||
return v_m[req.body.locale].format.number
|
||||
})
|
||||
],
|
||||
(req, res) => {
|
||||
const errors = validationResult(req)
|
||||
if (!errors.isEmpty()) return res.status(422).json(errors)
|
||||
|
||||
Cart_Item.findOne({product_id: req.body.product_id, user_id: req.body.user_id})
|
||||
.then(item => {
|
||||
item.quantity = Number(item.quantity) + Number(req.body.quantity)
|
||||
item.updated_at = dateformat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
|
||||
item.markModified('quantity')
|
||||
item.markModified('updated_at')
|
||||
item.save()
|
||||
return res.json({message: v_m[req.body.locale].response.success_save})
|
||||
})
|
||||
.catch(err => {
|
||||
const data = {
|
||||
user_id: req.body.user_id,
|
||||
product_id: req.body.product_id,
|
||||
quantity: req.body.quantity,
|
||||
created_at: dateformat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
|
||||
}
|
||||
const cartItem = new Cart_Item(data)
|
||||
cartItem.save((err, data) => {
|
||||
if (err) console.log(err)
|
||||
return res.json({message: v_m[req.body.locale].response.success_save})
|
||||
})
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
module.exports.getCartItems = [
|
||||
(req, res) => {
|
||||
Cart_Item.find({user_id: req.params.user_id}, (err, data) => {
|
||||
if (err) console.log(err)
|
||||
return res.json(data)
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
module.exports.updateCart = [
|
||||
(req, res) => {
|
||||
Cart_Item.findById(req.params.item_id)
|
||||
.then(item => {
|
||||
item.quantity = Number(req.body.quantity)
|
||||
item.updated_at = dateformat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
|
||||
item.markModified('quantity')
|
||||
item.markModified('updated_at')
|
||||
item.save()
|
||||
return res.json({message: v_m[req.body.locale].response.success_save})
|
||||
})
|
||||
.catch(err => {
|
||||
return res.status(404).json({message: v_m[req.body.locale].not_found.item_id})
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
module.exports.deleteFromCart = [
|
||||
(req, res) => {
|
||||
Cart_Item.findByIdAndDelete(req.params.item_id)
|
||||
.then(item => {
|
||||
Cart_Item.find({user_id: item.user_id})
|
||||
.then(items => {
|
||||
return res.json(items)
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
return res.status(404).json({message: v_m['en'].not_found.item_id})
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
////////////////////////////////////// order
|
||||
module.exports.addOrder = [
|
||||
[
|
||||
body('user_id')
|
||||
.custom((value, {req}) => {
|
||||
return User.findById(value)
|
||||
.then(user => {
|
||||
return true
|
||||
})
|
||||
.catch(err => {
|
||||
return Promise.reject(v_m[req.body.locale].not_found.user_id)
|
||||
})
|
||||
})
|
||||
],
|
||||
//////////////////// validation step
|
||||
(req, res, next) => {
|
||||
Cart_Item.find({user_id: req.body.user_id})
|
||||
.then(items => {
|
||||
// check if cart is not empty
|
||||
if (items.length) {
|
||||
// check product stock
|
||||
let outOfRun = []
|
||||
items.forEach(async (item, index) => {
|
||||
await Product.findById(item.product_id)
|
||||
.then(product => {
|
||||
if (product.stock < item.quantity) {
|
||||
outOfRun.push({
|
||||
product_id: product._id,
|
||||
category_id: product.category,
|
||||
stock: product.stock
|
||||
})
|
||||
item.remove()
|
||||
}
|
||||
if (index + 1 === items.length) {
|
||||
if (!outOfRun.length) return next()
|
||||
else return res.status(422).json(outOfRun)
|
||||
}
|
||||
})
|
||||
})
|
||||
} else {
|
||||
return res.status(404).json({message: v_m[req.body.locale].response.cart_empty})
|
||||
}
|
||||
})
|
||||
},
|
||||
//////////////////// save order
|
||||
(req, res) => {
|
||||
Cart_Item.find({user_id: req.body.user_id})
|
||||
.then(items => {
|
||||
// save the order
|
||||
const orderData = {
|
||||
user_id: req.body.user_id,
|
||||
number: Date.now(),
|
||||
created_at: dateformat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
|
||||
}
|
||||
const order = new Order(orderData)
|
||||
order.save((err, order) => {
|
||||
if (err) console.log(err)
|
||||
|
||||
// get price unit for items
|
||||
let unit = localeController.locales.filter(item => {
|
||||
return item.value === req.body.locale
|
||||
})[0].currency
|
||||
|
||||
// add incomplete status to order
|
||||
order.statuses.push({
|
||||
status: 'incomplete',
|
||||
created_at: dateformat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
|
||||
})
|
||||
|
||||
// add each item (Cart_Item result) to the order (saved Order result) and then remove it
|
||||
items.forEach((item, index) => {
|
||||
|
||||
// get the price of each item depend on order locale
|
||||
Product.findById(item.product_id).then(product => {
|
||||
let data = {
|
||||
product_id: item.product_id,
|
||||
quantity: item.quantity,
|
||||
price: product.product_details[req.body.locale].price,
|
||||
price_unit: unit,
|
||||
created_at: dateformat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
|
||||
}
|
||||
order.order_items.push(data)
|
||||
// reduce the product stock
|
||||
product.stock = Number(product.stock) - Number(item.quantity)
|
||||
product.save()
|
||||
item.remove()
|
||||
if (index + 1 === items.length) {
|
||||
order.save()
|
||||
return res.json(order)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
.catch(err => {
|
||||
return res.status(500).json(err)
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
module.exports.addAddressToOrder = [
|
||||
(req, res) => {
|
||||
Order.findById(req.params.order_id)
|
||||
.then(order => {
|
||||
if (!order.address) {
|
||||
User.findOne({'addresses._id': req.body.address_id})
|
||||
.then(user => {
|
||||
order.address = user.addresses.id(req.body.address_id)
|
||||
// add processing status to order
|
||||
order.statuses.push({
|
||||
status: 'processing',
|
||||
created_at: dateformat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
|
||||
})
|
||||
order.save()
|
||||
return res.json(order)
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
} else {
|
||||
return res.status(500).json({message: v_m[req.body.locale].response.already_has_address})
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
return res.status(404).json({message: v_m[req.body.locale].not_found.order_id})
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
module.exports.addStatusToOrder = [
|
||||
(req, res) => {
|
||||
Order.findById(req.params.order_id)
|
||||
.then(order => {
|
||||
order.statuses.push({
|
||||
status: req.body.status,
|
||||
created_at: dateformat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
|
||||
})
|
||||
order.save()
|
||||
return res.json(order)
|
||||
})
|
||||
.catch(err => {
|
||||
return res.status(500).json(err)
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
module.exports.getOrders = [
|
||||
(req, res) => {
|
||||
Order.find({user_id: req.params.user_id})
|
||||
.then(orders => {
|
||||
return res.json(orders)
|
||||
})
|
||||
.catch(err => {
|
||||
return res.status(500).json(err)
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
module.exports.getOneOrder = [
|
||||
(req, res) => {
|
||||
Order.findById(req.params.order_id)
|
||||
.then(order => {
|
||||
return res.json(order)
|
||||
})
|
||||
.catch(err => {
|
||||
return res.status(500).json(err)
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
////////////////////////////////////// get list of all orders for admin
|
||||
module.exports.getAllOrders = [
|
||||
(req, res) => {
|
||||
Order.find({})
|
||||
.then(orders => {
|
||||
return res.json(orders)
|
||||
})
|
||||
.catch(err => {
|
||||
return res.status(500).json(err)
|
||||
})
|
||||
}
|
||||
]
|
||||
@@ -2,162 +2,36 @@ const ProductCategory = require('../models/product/ProductCategory')
|
||||
const Product = require('../models/product/Product')
|
||||
const {body, validationResult} = require('express-validator')
|
||||
const dateformat = require('dateformat')
|
||||
const jimp = require('jimp')
|
||||
const fs = require('fs')
|
||||
|
||||
const v_m = require('../validation_messages')
|
||||
|
||||
module.exports.create = [
|
||||
[
|
||||
body('fa_name')
|
||||
.notEmpty().withMessage('نام نباید خالی باشد.')
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return ProductCategory.findOne({'category_details.fa.name': value})
|
||||
.then(category => {
|
||||
if (category) return Promise.reject('دسته بندی با این نام از قبل وجود دارد')
|
||||
return true
|
||||
})
|
||||
}
|
||||
),
|
||||
.notEmpty().withMessage(v_m['fa'].required.title),
|
||||
|
||||
body('en_name')
|
||||
.notEmpty().withMessage('نام نباید خالی باشد.')
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return ProductCategory.findOne({'category_details.en.name': value})
|
||||
.then(category => {
|
||||
if (category) return Promise.reject('دسته بندی با این نام از قبل وجود دارد')
|
||||
return true
|
||||
})
|
||||
}
|
||||
),
|
||||
|
||||
body('de_name')
|
||||
.notEmpty().withMessage('نام نباید خالی باشد.')
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return ProductCategory.findOne({'category_details.de.name': value})
|
||||
.then(category => {
|
||||
if (category) return Promise.reject('دسته بندی با این نام از قبل وجود دارد')
|
||||
return true
|
||||
})
|
||||
}
|
||||
),
|
||||
|
||||
body('tr_name')
|
||||
.notEmpty().withMessage('نام نباید خالی باشد.')
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return ProductCategory.findOne({'category_details.tr.name': value})
|
||||
.then(category => {
|
||||
if (category) return Promise.reject('دسته بندی با این نام از قبل وجود دارد')
|
||||
return true
|
||||
})
|
||||
}
|
||||
),
|
||||
|
||||
body('it_name')
|
||||
.notEmpty().withMessage('نام نباید خالی باشد.')
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return ProductCategory.findOne({'category_details.it.name': value})
|
||||
.then(category => {
|
||||
if (category) return Promise.reject('دسته بندی با این نام از قبل وجود دارد')
|
||||
return true
|
||||
})
|
||||
}
|
||||
),
|
||||
|
||||
body('fa_caption')
|
||||
.notEmpty().withMessage('توضیحات نباید خالی باشد.'),
|
||||
|
||||
body('en_caption')
|
||||
.notEmpty().withMessage('توضیحات نباید خالی باشد.'),
|
||||
|
||||
body('de_caption')
|
||||
.notEmpty().withMessage('توضیحات نباید خالی باشد.'),
|
||||
|
||||
body('tr_caption')
|
||||
.notEmpty().withMessage('توضیحات نباید خالی باشد.'),
|
||||
|
||||
body('it_caption')
|
||||
.notEmpty().withMessage('توضیحات نباید خالی باشد.')
|
||||
|
||||
.notEmpty().withMessage(v_m['fa'].required.title)
|
||||
],
|
||||
(req, res) => {
|
||||
const errors = validationResult(req)
|
||||
if (!errors.isEmpty()) return res.status(422).json({validation: errors.mapped()})
|
||||
|
||||
|
||||
let image
|
||||
let imageName
|
||||
let cover
|
||||
let coverName
|
||||
|
||||
if (req.files) {
|
||||
if (req.files.image) {
|
||||
image = req.files.image
|
||||
imageName = 'categoryImage_' + Date.now() + '.' + image.mimetype.split('/')[1]
|
||||
if (image.mimetype.split('/')[1] !== 'png') return res.status(422).json({validation: {image: {msg: 'فرمت عکس باید png باشد.'}}})
|
||||
} else {
|
||||
return res.status(422).json({validation: {image: {msg: 'عکس اجباری است.'}}})
|
||||
}
|
||||
if (req.files.cover) {
|
||||
cover = req.files.cover
|
||||
coverName = 'categoryCover_' + Date.now() + '.' + cover.mimetype.split('/')[1]
|
||||
if (cover.size / 1024 > 500) return res.status(422).json({validation: {cover: {msg: 'حجم کاور نباید بیشتر از 500 کیلوبایت باشد'}}})
|
||||
cover.mv(`./static/uploads/images/products/category/${coverName}`)
|
||||
} else {
|
||||
return res.status(422).json({validation: {cover: {msg: 'کاور اجباری است.'}}})
|
||||
}
|
||||
} else {
|
||||
return res.status(422).json({
|
||||
validation: {
|
||||
image: {msg: 'عکس اجباری است.'},
|
||||
cover: {msg: 'کاور اجباری است.'}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const data = {
|
||||
cover: coverName,
|
||||
category_details: {
|
||||
fa: {
|
||||
name: req.body.fa_name,
|
||||
caption: req.body.fa_caption
|
||||
name: req.body.fa_name
|
||||
},
|
||||
en: {
|
||||
name: req.body.en_name,
|
||||
caption: req.body.en_caption
|
||||
},
|
||||
de: {
|
||||
name: req.body.de_name,
|
||||
caption: req.body.de_caption
|
||||
},
|
||||
tr: {
|
||||
name: req.body.tr_name,
|
||||
caption: req.body.tr_caption
|
||||
},
|
||||
it: {
|
||||
name: req.body.it_name,
|
||||
caption: req.body.it_caption
|
||||
name: req.body.en_name
|
||||
}
|
||||
},
|
||||
created_at: dateformat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
|
||||
}
|
||||
jimp.read(image.data).then(img => {
|
||||
img
|
||||
.cover(380, 230)
|
||||
.write(`./static/uploads/images/products/category/${imageName}`, err => {
|
||||
if (err) console.log(err)
|
||||
data.image = imageName
|
||||
|
||||
const category = new ProductCategory(data)
|
||||
category.save(err => {
|
||||
if (err) return res.status(500).json({message: err})
|
||||
return res.json({message: 'دسته بندی با موفقیت ثبت شد.'})
|
||||
})
|
||||
})
|
||||
const category = new ProductCategory(data)
|
||||
category.save(err => {
|
||||
if (err) return res.status(500).json({message: err})
|
||||
return res.json({message: v_m['fa'].response.success_save})
|
||||
})
|
||||
}
|
||||
]
|
||||
@@ -186,154 +60,30 @@ module.exports.getOne = [
|
||||
module.exports.update = [
|
||||
[
|
||||
body('fa_name')
|
||||
.notEmpty().withMessage('نام نباید خالی باشد.')
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return ProductCategory.findOne({'category_details.fa.name': value})
|
||||
.then(category => {
|
||||
if (category && category._id.toString() !== req.params.id) return Promise.reject('دسته بندی با این نام از قبل وجود دارد')
|
||||
return true
|
||||
})
|
||||
}
|
||||
),
|
||||
.notEmpty().withMessage(v_m['fa'].required.title),
|
||||
|
||||
body('en_name')
|
||||
.notEmpty().withMessage('نام نباید خالی باشد.')
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return ProductCategory.findOne({'category_details.en.name': value})
|
||||
.then(category => {
|
||||
if (category && category._id.toString() !== req.params.id) return Promise.reject('دسته بندی با این نام از قبل وجود دارد')
|
||||
return true
|
||||
})
|
||||
}
|
||||
),
|
||||
|
||||
body('de_name')
|
||||
.notEmpty().withMessage('نام نباید خالی باشد.')
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return ProductCategory.findOne({'category_details.de.name': value})
|
||||
.then(category => {
|
||||
if (category && category._id.toString() !== req.params.id) return Promise.reject('دسته بندی با این نام از قبل وجود دارد')
|
||||
return true
|
||||
})
|
||||
}
|
||||
),
|
||||
|
||||
body('tr_name')
|
||||
.notEmpty().withMessage('نام نباید خالی باشد.')
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return ProductCategory.findOne({'category_details.tr.name': value})
|
||||
.then(category => {
|
||||
if (category && category._id.toString() !== req.params.id) return Promise.reject('دسته بندی با این نام از قبل وجود دارد')
|
||||
return true
|
||||
})
|
||||
}
|
||||
),
|
||||
|
||||
body('it_name')
|
||||
.notEmpty().withMessage('نام نباید خالی باشد.')
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return ProductCategory.findOne({'category_details.it.name': value})
|
||||
.then(category => {
|
||||
if (category && category._id.toString() !== req.params.id) return Promise.reject('دسته بندی با این نام از قبل وجود دارد')
|
||||
return true
|
||||
})
|
||||
}
|
||||
),
|
||||
|
||||
body('fa_caption')
|
||||
.notEmpty().withMessage('توضیحات نباید خالی باشد.'),
|
||||
|
||||
body('en_caption')
|
||||
.notEmpty().withMessage('توضیحات نباید خالی باشد.'),
|
||||
|
||||
body('de_caption')
|
||||
.notEmpty().withMessage('توضیحات نباید خالی باشد.'),
|
||||
|
||||
body('tr_caption')
|
||||
.notEmpty().withMessage('توضیحات نباید خالی باشد.'),
|
||||
|
||||
body('it_caption')
|
||||
.notEmpty().withMessage('توضیحات نباید خالی باشد.')
|
||||
.notEmpty().withMessage(v_m['fa'].required.title)
|
||||
],
|
||||
(req, res) => {
|
||||
// check validation results
|
||||
const errors = validationResult(req)
|
||||
if (!errors.isEmpty()) return res.status(422).json({validation: errors.mapped()})
|
||||
|
||||
|
||||
let image
|
||||
let imageName
|
||||
let cover
|
||||
let coverName
|
||||
|
||||
const data = {
|
||||
category_details: {
|
||||
fa: {
|
||||
name: req.body.fa_name,
|
||||
caption: req.body.fa_caption
|
||||
name: req.body.fa_name
|
||||
},
|
||||
en: {
|
||||
name: req.body.en_name,
|
||||
caption: req.body.en_caption
|
||||
},
|
||||
de: {
|
||||
name: req.body.de_name,
|
||||
caption: req.body.de_caption
|
||||
},
|
||||
tr: {
|
||||
name: req.body.tr_name,
|
||||
caption: req.body.tr_caption
|
||||
},
|
||||
it: {
|
||||
name: req.body.it_name,
|
||||
caption: req.body.it_caption
|
||||
name: req.body.en_name
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (req.files) {
|
||||
if (req.files.image) {
|
||||
image = req.files.image
|
||||
imageName = 'categoryImage_' + Date.now() + '.' + image.mimetype.split('/')[1]
|
||||
if (image.mimetype.split('/')[1] !== 'png') return res.status(422).json({validation: {image: {msg: 'فرمت عکس باید png باشد.'}}})
|
||||
data.image = imageName
|
||||
|
||||
jimp.read(image.data).then(img => {
|
||||
img
|
||||
.cover(380, 230)
|
||||
.write(`./static/uploads/images/products/category/${imageName}`, err => {
|
||||
if (err) console.log(err)
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
if (req.files.cover) {
|
||||
cover = req.files.cover
|
||||
coverName = 'categoryCover_' + Date.now() + '.' + cover.mimetype.split('/')[1]
|
||||
if (cover.size / 1024 > 500) return res.status(422).json({validation: {cover: {msg: 'حجم کاور نباید بیشتر از 500 کیلوبایت باشد'}}})
|
||||
cover.mv(`./static/uploads/images/products/category/${coverName}`)
|
||||
data.cover = coverName
|
||||
}
|
||||
}
|
||||
|
||||
ProductCategory.findByIdAndUpdate(req.params.id, data, (err, oldData) => {
|
||||
if (err) return res.status(404).json({message: err})
|
||||
if (image && image.data) fs.unlink(`./static/${oldData.image}`, err => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
if (cover && cover.data) fs.unlink(`./static/${oldData.cover}`, err => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
ProductCategory.findById(oldData._id)
|
||||
.then(category => {
|
||||
return res.json(category)
|
||||
})
|
||||
return res.json({message: v_m['fa'].response.success_save})
|
||||
})
|
||||
}
|
||||
]
|
||||
@@ -347,15 +97,7 @@ module.exports.delete = [
|
||||
else {
|
||||
ProductCategory.findByIdAndDelete(req.params.id, (err, category) => {
|
||||
if (err) return res.status(404).json({message: err})
|
||||
if (category) {
|
||||
fs.unlink(`./static/${category.image}`, err => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
fs.unlink(`./static/${category.cover}`, err => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
return res.json({message: 'دسته بندی حذف شد.'})
|
||||
}
|
||||
return res.json({message: v_m['fa'].response.success_remove})
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,168 +1,207 @@
|
||||
const Product = require('../models/product/Product')
|
||||
const CartItem = require('../models/user/Cart_item')
|
||||
const Order = require('../models/user/Order')
|
||||
const {body, validationResult} = require('express-validator')
|
||||
const dateformat = require('dateformat')
|
||||
const jimp = require('jimp')
|
||||
const fs = require('fs')
|
||||
|
||||
const v_m = require('../validation_messages')
|
||||
|
||||
////////////////////////////////////////// products controllers
|
||||
module.exports.createProduct = [
|
||||
[
|
||||
body('fa_name')
|
||||
.isLength({min: 2}).withMessage('حداقل 2 کاراکتر')
|
||||
.notEmpty().withMessage(v_m['fa'].required.title)
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return Product.findOne({'product_details.fa.name': value})
|
||||
.then(product => {
|
||||
if (product) return Promise.reject('محصول با این نام از قبل وجود دارد.')
|
||||
if (product) return Promise.reject(v_m['fa'].duplicated.name)
|
||||
else return true
|
||||
})
|
||||
}),
|
||||
|
||||
body('en_name')
|
||||
.if((value, {req}) => value !== '')
|
||||
.notEmpty().withMessage(v_m['fa'].required.title)
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return Product.findOne({'product_details.en.name': value})
|
||||
.then(product => {
|
||||
if (product) return Promise.reject('محصول با این نام از قبل وجود دارد.')
|
||||
if (product) return Promise.reject(v_m['fa'].duplicated.name)
|
||||
else return true
|
||||
})
|
||||
}),
|
||||
|
||||
|
||||
body('de_name')
|
||||
.if((value, {req}) => value !== '')
|
||||
.custom((value, {req}) => {
|
||||
return Product.findOne({'product_details.de.name': value})
|
||||
.then(product => {
|
||||
if (product) return Promise.reject('محصول با این نام از قبل وجود دارد.')
|
||||
else return true
|
||||
})
|
||||
}),
|
||||
|
||||
|
||||
body('tr_name')
|
||||
.if((value, {req}) => value !== '')
|
||||
.custom((value, {req}) => {
|
||||
return Product.findOne({'product_details.tr.name': value})
|
||||
.then(product => {
|
||||
if (product) return Promise.reject('محصول با این نام از قبل وجود دارد.')
|
||||
else return true
|
||||
})
|
||||
}),
|
||||
|
||||
|
||||
body('it_name')
|
||||
.if((value, {req}) => value !== '')
|
||||
.custom((value, {req}) => {
|
||||
return Product.findOne({'product_details.it.name': value})
|
||||
.then(product => {
|
||||
if (product) return Promise.reject('محصول با این نام از قبل وجود دارد.')
|
||||
else return true
|
||||
})
|
||||
}),
|
||||
|
||||
body('fa_description')
|
||||
.isLength({min: 2}).withMessage('حداقل 2 کاراکتر'),
|
||||
|
||||
body('fa_price')
|
||||
.notEmpty().withMessage('قیمت را وارد کنید.')
|
||||
body('fa_short_description')
|
||||
.notEmpty().withMessage(v_m['fa'].required.caption)
|
||||
.bail()
|
||||
.isNumeric().withMessage('قیمت باید از جنس عدد باشد'),
|
||||
.isLength({max: 100}).withMessage(v_m['fa'].max_char.max100),
|
||||
|
||||
body('en_price')
|
||||
.notEmpty().withMessage('قیمت را وارد کنید.')
|
||||
body('en_short_description')
|
||||
.notEmpty().withMessage(v_m['fa'].required.caption)
|
||||
.bail()
|
||||
.isNumeric().withMessage('قیمت باید از جنس عدد باشد'),
|
||||
.isLength({max: 100}).withMessage(v_m['fa'].max_char.max100),
|
||||
|
||||
body('de_price')
|
||||
.notEmpty().withMessage('قیمت را وارد کنید.')
|
||||
.bail()
|
||||
.isNumeric().withMessage('قیمت باید از جنس عدد باشد'),
|
||||
body('fa_page_title')
|
||||
.notEmpty().withMessage(v_m['fa'].required.title),
|
||||
|
||||
body('tr_price')
|
||||
.notEmpty().withMessage('قیمت را وارد کنید.')
|
||||
.bail()
|
||||
.isNumeric().withMessage('قیمت باید از جنس عدد باشد'),
|
||||
body('en_page_title')
|
||||
.notEmpty().withMessage(v_m['fa'].required.title),
|
||||
|
||||
body('it_price')
|
||||
.notEmpty().withMessage('قیمت را وارد کنید.')
|
||||
.bail()
|
||||
.isNumeric().withMessage('قیمت باید از جنس عدد باشد'),
|
||||
body('fa_page_description')
|
||||
.notEmpty().withMessage(v_m['fa'].required.caption),
|
||||
|
||||
body('stock')
|
||||
.notEmpty().withMessage('موجودی را وارد کنید.')
|
||||
.bail()
|
||||
.isNumeric().withMessage('موجودی باید از جنس عدد باشد'),
|
||||
body('en_page_description')
|
||||
.notEmpty().withMessage(v_m['fa'].required.caption),
|
||||
|
||||
body('en_page_description')
|
||||
.notEmpty().withMessage(v_m['fa'].required.caption),
|
||||
|
||||
body('category')
|
||||
.notEmpty().withMessage('دسته بندی را انتخاب کنید.')
|
||||
.notEmpty().withMessage(v_m['fa'].required.category)
|
||||
],
|
||||
(req, res) => {
|
||||
async (req, res) => {
|
||||
const errors = validationResult(req)
|
||||
if (!errors.isEmpty()) return res.status(422).json({validation: errors.mapped()})
|
||||
if (!req.files || !req.files.cover) return res.status(422).json({validation: {cover: {msg: v_m['fa'].required.cover}}})
|
||||
|
||||
let image
|
||||
let imageName
|
||||
if (req.files && req.files.image) {
|
||||
image = req.files.image
|
||||
imageName = 'product_' + Date.now() + '.' + image.mimetype.split('/')[1]
|
||||
} else {
|
||||
return res.status(422).json({validation: {image: {msg: 'عکس اجباری است.'}}})
|
||||
|
||||
let cover = 'product_' + Date.now() + '.' + req.files.cover.mimetype.split('/')[1]
|
||||
let more_section_image1 = null
|
||||
let more_section_image2 = null
|
||||
let render_image1 = null
|
||||
let render_image2 = null
|
||||
let chart_image = null
|
||||
|
||||
//// generate files names
|
||||
if (req.files) {
|
||||
if (req.files.more_section_image1) {
|
||||
more_section_image1 = 'product_' + Date.now() + 1 + '.' + req.files.more_section_image1.mimetype.split('/')[1]
|
||||
}
|
||||
if (req.files.more_section_image2) {
|
||||
more_section_image2 = 'product_' + Date.now() + 2 + '.' + req.files.more_section_image2.mimetype.split('/')[1]
|
||||
}
|
||||
if (req.files.render_image1) {
|
||||
render_image1 = 'product_' + Date.now() + 3 + '.' + req.files.render_image1.mimetype.split('/')[1]
|
||||
}
|
||||
if (req.files.render_image2) {
|
||||
render_image2 = 'product_' + Date.now() + 4 + '.' + req.files.render_image2.mimetype.split('/')[1]
|
||||
}
|
||||
if (req.files.chart_image) {
|
||||
chart_image = 'product_' + Date.now() + 5 + '.' + req.files.chart_image.mimetype.split('/')[1]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const data = {
|
||||
price: req.body.price,
|
||||
stock: req.body.stock,
|
||||
cover: cover,
|
||||
category: req.body.category,
|
||||
more_section: req.body.more_section,
|
||||
download_section: req.body.download_section,
|
||||
product_details: {
|
||||
fa: {
|
||||
name: req.body.fa_name,
|
||||
description: req.body.fa_description,
|
||||
price: req.body.fa_price
|
||||
short_description: req.body.fa_short_description,
|
||||
page_title: req.body.fa_page_title,
|
||||
page_description: req.body.fa_page_description,
|
||||
more_title1: req.body.fa_more_title1,
|
||||
more_description1: req.body.fa_more_description1,
|
||||
more_title2: req.body.fa_more_title2,
|
||||
more_description2: req.body.fa_more_description2,
|
||||
render_caption1: req.body.fa_render_caption1,
|
||||
render_caption2: req.body.fa_render_caption2,
|
||||
chart_title: req.body.fa_chart_title,
|
||||
chart_description: req.body.fa_chart_description
|
||||
},
|
||||
en: {
|
||||
name: req.body.en_name,
|
||||
description: req.body.en_description,
|
||||
price: req.body.en_price
|
||||
},
|
||||
de: {
|
||||
name: req.body.de_name,
|
||||
description: req.body.de_description,
|
||||
price: req.body.de_price
|
||||
},
|
||||
it: {
|
||||
name: req.body.it_name,
|
||||
description: req.body.it_description,
|
||||
price: req.body.it_price
|
||||
},
|
||||
tr: {
|
||||
name: req.body.tr_name,
|
||||
description: req.body.tr_description,
|
||||
price: req.body.tr_price
|
||||
short_description: req.body.en_short_description,
|
||||
page_title: req.body.en_page_title,
|
||||
page_description: req.body.en_page_description,
|
||||
more_title1: req.body.en_more_title1,
|
||||
more_description1: req.body.en_more_description1,
|
||||
more_title2: req.body.en_more_title2,
|
||||
more_description2: req.body.en_more_description2,
|
||||
render_caption1: req.body.en_render_caption1,
|
||||
render_caption2: req.body.en_render_caption2,
|
||||
chart_title: req.body.en_chart_title,
|
||||
chart_description: req.body.en_chart_description
|
||||
}
|
||||
},
|
||||
created_at: dateformat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
|
||||
}
|
||||
if (req.files.more_section_image1) data.more_section_image1 = more_section_image1
|
||||
if (req.files.more_section_image2) data.more_section_image2 = more_section_image2
|
||||
if (req.files.render_image1) data.render_image1 = render_image1
|
||||
if (req.files.render_image2) data.render_image2 = render_image2
|
||||
if (req.files.chart_image) data.chart_image = chart_image
|
||||
|
||||
jimp.read(image.data)
|
||||
.then(img => {
|
||||
img
|
||||
.resize(250, jimp.AUTO)
|
||||
.cover(250, 250)
|
||||
.write(`./static/uploads/images/products/${imageName}`)
|
||||
|
||||
//// write to database
|
||||
data.image = imageName
|
||||
const product = new Product(data)
|
||||
product.save((err, data) => {
|
||||
if (err) console.log(err)
|
||||
return res.json(data)
|
||||
})
|
||||
})
|
||||
//// save images
|
||||
if (req.files) {
|
||||
if (req.files.cover) {
|
||||
await jimp.read(req.files.cover.data)
|
||||
.then(img => {
|
||||
img
|
||||
.resize(470, jimp.AUTO)
|
||||
.cover(470, 390)
|
||||
.quality(70)
|
||||
.write(`./static/uploads/images/products/${cover}`)
|
||||
})
|
||||
}
|
||||
if (req.files.more_section_image1) {
|
||||
await jimp.read(req.files.more_section_image1.data)
|
||||
.then(img => {
|
||||
img
|
||||
.resize(778, jimp.AUTO)
|
||||
.cover(778, 395)
|
||||
.quality(70)
|
||||
.write(`./static/uploads/images/products/${more_section_image1}`)
|
||||
})
|
||||
}
|
||||
if (req.files.more_section_image2) {
|
||||
await jimp.read(req.files.more_section_image2.data)
|
||||
.then(img => {
|
||||
img
|
||||
.resize(778, jimp.AUTO)
|
||||
.cover(778, 395)
|
||||
.quality(70)
|
||||
.write(`./static/uploads/images/products/${more_section_image2}`)
|
||||
})
|
||||
}
|
||||
if (req.files.render_image1) {
|
||||
await jimp.read(req.files.render_image1.data)
|
||||
.then(img => {
|
||||
img
|
||||
.resize(300, jimp.AUTO)
|
||||
.cover(300, 300)
|
||||
.quality(70)
|
||||
.write(`./static/uploads/images/products/${render_image1}`)
|
||||
})
|
||||
}
|
||||
if (req.files.render_image2) {
|
||||
await jimp.read(req.files.render_image2.data)
|
||||
.then(img => {
|
||||
img
|
||||
.resize(300, jimp.AUTO)
|
||||
.cover(300, 300)
|
||||
.quality(70)
|
||||
.write(`./static/uploads/images/products/${render_image2}`)
|
||||
})
|
||||
}
|
||||
if (req.files.chart_image) {
|
||||
await jimp.read(req.files.chart_image.data)
|
||||
.then(img => {
|
||||
img
|
||||
.quality(100)
|
||||
.write(`./static/uploads/images/products/${chart_image}`)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
//// write to database
|
||||
const product = new Product(data)
|
||||
product.save((err, data) => {
|
||||
if (err) console.log(err)
|
||||
return res.json(data)
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
@@ -179,7 +218,7 @@ module.exports.getAllProductsByCategory = [
|
||||
|
||||
module.exports.getAllProducts = [
|
||||
(req, res) => {
|
||||
Product.find({}).select('image stock category product_details').exec((err, products) => {
|
||||
Product.find({}).select('cover category product_details').exec((err, products) => {
|
||||
if (err) console.log(err)
|
||||
return res.json(products)
|
||||
})
|
||||
@@ -198,181 +237,233 @@ module.exports.getOneProduct = [
|
||||
module.exports.updateProduct = [
|
||||
[
|
||||
body('fa_name')
|
||||
.isLength({min: 2}).withMessage('حداقل 2 کاراکتر')
|
||||
.notEmpty().withMessage(v_m['fa'].required.title)
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return Product.findOne({'product_details.fa.name': value})
|
||||
.then(product => {
|
||||
if (product && product._id.toString() !== req.params.id) return Promise.reject('محصول با این نام از قبل وجود دارد.')
|
||||
if (product && product._id.toString() !== req.params.id) return Promise.reject(v_m['fa'].duplicated.name)
|
||||
else return true
|
||||
})
|
||||
}),
|
||||
|
||||
body('en_name')
|
||||
.if((value, {req}) => value !== '')
|
||||
.notEmpty().withMessage(v_m['fa'].required.title)
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return Product.findOne({'product_details.en.name': value})
|
||||
.then(product => {
|
||||
if (product && product._id.toString() !== req.params.id) return Promise.reject('محصول با این نام از قبل وجود دارد.')
|
||||
if (product && product._id.toString() !== req.params.id) return Promise.reject(v_m['fa'].duplicated.name)
|
||||
else return true
|
||||
})
|
||||
}),
|
||||
|
||||
body('de_name')
|
||||
.if((value, {req}) => value !== '')
|
||||
.custom((value, {req}) => {
|
||||
return Product.findOne({'product_details.de.name': value})
|
||||
.then(product => {
|
||||
if (product && product._id.toString() !== req.params.id) return Promise.reject('محصول با این نام از قبل وجود دارد.')
|
||||
else return true
|
||||
})
|
||||
}),
|
||||
|
||||
body('tr_name')
|
||||
.if((value, {req}) => value !== '')
|
||||
.custom((value, {req}) => {
|
||||
return Product.findOne({'product_details.tr.name': value})
|
||||
.then(product => {
|
||||
if (product && product._id.toString() !== req.params.id) return Promise.reject('محصول با این نام از قبل وجود دارد.')
|
||||
else return true
|
||||
})
|
||||
}),
|
||||
|
||||
body('it_name')
|
||||
.if((value, {req}) => value !== '')
|
||||
.custom((value, {req}) => {
|
||||
return Product.findOne({'product_details.it.name': value})
|
||||
.then(product => {
|
||||
if (product && product._id.toString() !== req.params.id) return Promise.reject('محصول با این نام از قبل وجود دارد.')
|
||||
else return true
|
||||
})
|
||||
}),
|
||||
|
||||
body('fa_description')
|
||||
.isLength({min: 2}).withMessage('حداقل 2 کاراکتر'),
|
||||
|
||||
body('fa_price')
|
||||
.notEmpty().withMessage('قیمت را وارد کنید.')
|
||||
body('fa_short_description')
|
||||
.notEmpty().withMessage(v_m['fa'].required.caption)
|
||||
.bail()
|
||||
.isNumeric().withMessage('قیمت باید از جنس عدد باشد'),
|
||||
.isLength({max: 100}).withMessage(v_m['fa'].max_char.max100),
|
||||
|
||||
body('en_price')
|
||||
.notEmpty().withMessage('قیمت را وارد کنید.')
|
||||
body('en_short_description')
|
||||
.notEmpty().withMessage(v_m['fa'].required.caption)
|
||||
.bail()
|
||||
.isNumeric().withMessage('قیمت باید از جنس عدد باشد'),
|
||||
.isLength({max: 100}).withMessage(v_m['fa'].max_char.max100),
|
||||
|
||||
body('de_price')
|
||||
.notEmpty().withMessage('قیمت را وارد کنید.')
|
||||
.bail()
|
||||
.isNumeric().withMessage('قیمت باید از جنس عدد باشد'),
|
||||
body('fa_page_title')
|
||||
.notEmpty().withMessage(v_m['fa'].required.title),
|
||||
|
||||
body('tr_price')
|
||||
.notEmpty().withMessage('قیمت را وارد کنید.')
|
||||
.bail()
|
||||
.isNumeric().withMessage('قیمت باید از جنس عدد باشد'),
|
||||
body('en_page_title')
|
||||
.notEmpty().withMessage(v_m['fa'].required.title),
|
||||
|
||||
body('it_price')
|
||||
.notEmpty().withMessage('قیمت را وارد کنید.')
|
||||
.bail()
|
||||
.isNumeric().withMessage('قیمت باید از جنس عدد باشد'),
|
||||
body('fa_page_description')
|
||||
.notEmpty().withMessage(v_m['fa'].required.caption),
|
||||
|
||||
body('stock')
|
||||
.notEmpty().withMessage('موجودی را وارد کنید.')
|
||||
.bail()
|
||||
.isNumeric().withMessage('موجودی باید از جنس عدد باشد'),
|
||||
body('en_page_description')
|
||||
.notEmpty().withMessage(v_m['fa'].required.caption),
|
||||
|
||||
body('en_page_description')
|
||||
.notEmpty().withMessage(v_m['fa'].required.caption),
|
||||
|
||||
body('category')
|
||||
.notEmpty().withMessage('دسته بندی را انتخاب کنید.')
|
||||
.notEmpty().withMessage(v_m['fa'].required.category)
|
||||
],
|
||||
(req, res) => {
|
||||
async (req, res) => {
|
||||
const errors = validationResult(req)
|
||||
if (!errors.isEmpty()) return res.status(422).json({validation: errors.mapped()})
|
||||
|
||||
let cover = null
|
||||
let more_section_image1 = null
|
||||
let more_section_image2 = null
|
||||
let render_image1 = null
|
||||
let render_image2 = null
|
||||
let chart_image = null
|
||||
|
||||
//// generate files names
|
||||
if (req.files) {
|
||||
if (req.files.cover) {
|
||||
cover = 'product_' + Date.now() + '.' + req.files.cover.mimetype.split('/')[1]
|
||||
}
|
||||
if (req.files.more_section_image1) {
|
||||
more_section_image1 = 'product_' + Date.now() + 1 + '.' + req.files.more_section_image1.mimetype.split('/')[1]
|
||||
}
|
||||
if (req.files.more_section_image2) {
|
||||
more_section_image2 = 'product_' + Date.now() + 2 + '.' + req.files.more_section_image2.mimetype.split('/')[1]
|
||||
}
|
||||
if (req.files.render_image1) {
|
||||
render_image1 = 'product_' + Date.now() + 3 + '.' + req.files.render_image1.mimetype.split('/')[1]
|
||||
}
|
||||
if (req.files.render_image2) {
|
||||
render_image2 = 'product_' + Date.now() + 4 + '.' + req.files.render_image2.mimetype.split('/')[1]
|
||||
}
|
||||
if (req.files.chart_image) {
|
||||
chart_image = 'product_' + Date.now() + 5 + '.' + req.files.chart_image.mimetype.split('/')[1]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const data = {
|
||||
price: req.body.price,
|
||||
stock: req.body.stock,
|
||||
category: req.body.category,
|
||||
more_section: req.body.more_section,
|
||||
download_section: req.body.download_section,
|
||||
product_details: {
|
||||
fa: {
|
||||
name: req.body.fa_name,
|
||||
description: req.body.fa_description,
|
||||
price: req.body.fa_price
|
||||
short_description: req.body.fa_short_description,
|
||||
page_title: req.body.fa_page_title,
|
||||
page_description: req.body.fa_page_description,
|
||||
more_title1: req.body.fa_more_title1,
|
||||
more_description1: req.body.fa_more_description1,
|
||||
more_title2: req.body.fa_more_title2,
|
||||
more_description2: req.body.fa_more_description2,
|
||||
render_caption1: req.body.fa_render_caption1,
|
||||
render_caption2: req.body.fa_render_caption2,
|
||||
chart_title: req.body.fa_chart_title,
|
||||
chart_description: req.body.fa_chart_description
|
||||
},
|
||||
en: {
|
||||
name: req.body.en_name,
|
||||
description: req.body.en_description,
|
||||
price: req.body.en_price
|
||||
},
|
||||
de: {
|
||||
name: req.body.de_name,
|
||||
description: req.body.de_description,
|
||||
price: req.body.de_price
|
||||
},
|
||||
it: {
|
||||
name: req.body.it_name,
|
||||
description: req.body.it_description,
|
||||
price: req.body.it_price
|
||||
},
|
||||
tr: {
|
||||
name: req.body.tr_name,
|
||||
description: req.body.tr_description,
|
||||
price: req.body.tr_price
|
||||
short_description: req.body.en_short_description,
|
||||
page_title: req.body.en_page_title,
|
||||
page_description: req.body.en_page_description,
|
||||
more_title1: req.body.en_more_title1,
|
||||
more_description1: req.body.en_more_description1,
|
||||
more_title2: req.body.en_more_title2,
|
||||
more_description2: req.body.en_more_description2,
|
||||
render_caption1: req.body.en_render_caption1,
|
||||
render_caption2: req.body.en_render_caption2,
|
||||
chart_title: req.body.en_chart_title,
|
||||
chart_description: req.body.en_chart_description
|
||||
}
|
||||
},
|
||||
updated_at: dateformat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
|
||||
created_at: dateformat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
|
||||
}
|
||||
|
||||
if (req.files) {
|
||||
if (req.files.cover) data.cover = cover
|
||||
if (req.files.more_section_image1) data.more_section_image1 = more_section_image1
|
||||
if (req.files.more_section_image2) data.more_section_image2 = more_section_image2
|
||||
if (req.files.render_image1) data.render_image1 = render_image1
|
||||
if (req.files.render_image2) data.render_image2 = render_image2
|
||||
if (req.files.chart_image) data.chart_image = chart_image
|
||||
}
|
||||
|
||||
let image
|
||||
let imageName
|
||||
if (req.files && req.files.image) {
|
||||
image = req.files.image
|
||||
imageName = 'product_' + Date.now() + '.' + image.mimetype.split('/')[1]
|
||||
data.image = imageName
|
||||
|
||||
jimp.read(image.data)
|
||||
.then(img => {
|
||||
img
|
||||
.resize(250, jimp.AUTO)
|
||||
.cover(250, 250)
|
||||
.write(`./static/uploads/images/products/${imageName}`)
|
||||
|
||||
Product.findByIdAndUpdate(req.params.id, data, (err, oldData) => {
|
||||
if (err) console.log(err)
|
||||
fs.unlink(`./static/${oldData.image}`, (err) => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
return res.json({message: 'product updated.'})
|
||||
//// save images
|
||||
if (req.files) {
|
||||
if (req.files.cover) {
|
||||
await jimp.read(req.files.cover.data)
|
||||
.then(img => {
|
||||
img
|
||||
.resize(470, jimp.AUTO)
|
||||
.cover(470, 390)
|
||||
.quality(70)
|
||||
.write(`./static/uploads/images/products/${cover}`)
|
||||
})
|
||||
})
|
||||
} else {
|
||||
Product.findByIdAndUpdate(req.params.id, data, (err, oldData) => {
|
||||
if (err) console.log(err)
|
||||
return res.json({message: 'product updated.'})
|
||||
})
|
||||
}
|
||||
if (req.files.more_section_image1) {
|
||||
await jimp.read(req.files.more_section_image1.data)
|
||||
.then(img => {
|
||||
img
|
||||
.resize(778, jimp.AUTO)
|
||||
.cover(778, 395)
|
||||
.quality(70)
|
||||
.write(`./static/uploads/images/products/${more_section_image1}`)
|
||||
})
|
||||
}
|
||||
if (req.files.more_section_image2) {
|
||||
await jimp.read(req.files.more_section_image2.data)
|
||||
.then(img => {
|
||||
img
|
||||
.resize(778, jimp.AUTO)
|
||||
.cover(778, 395)
|
||||
.quality(70)
|
||||
.write(`./static/uploads/images/products/${more_section_image2}`)
|
||||
})
|
||||
}
|
||||
if (req.files.render_image1) {
|
||||
await jimp.read(req.files.render_image1.data)
|
||||
.then(img => {
|
||||
img
|
||||
.resize(300, jimp.AUTO)
|
||||
.cover(300, 300)
|
||||
.quality(70)
|
||||
.write(`./static/uploads/images/products/${render_image1}`)
|
||||
})
|
||||
}
|
||||
if (req.files.render_image2) {
|
||||
await jimp.read(req.files.render_image2.data)
|
||||
.then(img => {
|
||||
img
|
||||
.resize(300, jimp.AUTO)
|
||||
.cover(300, 300)
|
||||
.quality(70)
|
||||
.write(`./static/uploads/images/products/${render_image2}`)
|
||||
})
|
||||
}
|
||||
if (req.files.chart_image) {
|
||||
await jimp.read(req.files.chart_image.data)
|
||||
.then(img => {
|
||||
img
|
||||
.quality(100)
|
||||
.write(`./static/uploads/images/products/${chart_image}`)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
//// write to database
|
||||
Product.findByIdAndUpdate(req.params.id, data, (err, oldData) => {
|
||||
if (err) console.log(err)
|
||||
if (req.files) {
|
||||
if (req.files.cover) fs.unlink(`./static/${oldData.cover}`, err => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
if (req.files.more_section_image1 && oldData.more_section_image1) fs.unlink(`./static/${oldData.more_section_image1}`, err => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
if (req.files.more_section_image2 && oldData.more_section_image2) fs.unlink(`./static/${oldData.more_section_image2}`, err => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
if (req.files.render_image1 && oldData.render_image1) fs.unlink(`./static/${oldData.render_image1}`, err => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
if (req.files.render_image2 && oldData.render_image2) fs.unlink(`./static/${oldData.render_image2}`, err => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
if (req.files.chart_image && oldData.chart_image) fs.unlink(`./static/${oldData.chart_image}`, err => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
}
|
||||
Product.findById(oldData._id, (err, data) => {
|
||||
if (err) console.log(err)
|
||||
return res.json(data)
|
||||
})
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
module.exports.deleteProduct = [
|
||||
(req, res) => {
|
||||
CartItem.findOne({product_id: req.params.id}, (err, item) => {
|
||||
Product.findByIdAndDelete(req.params.id, (err, product) => {
|
||||
if (err) console.log(err)
|
||||
if (item) {
|
||||
return res.status(401).json({message: 'این محصول درون سبد خرید ثبت شده و نمیتوان آن را حذف کرد.'})
|
||||
} else {
|
||||
Order.findOne({'order_items.product_id': req.params.id}, (err, order) => {
|
||||
if (err) console.log(err)
|
||||
if (order) {
|
||||
return res.status(401).json({message: 'این محصول درون سفارش ثبت شده و نمیتوان آن را حذف کرد.'})
|
||||
} else {
|
||||
Product.findByIdAndDelete(req.params.id, (err, product) => {
|
||||
if (err) console.log(err)
|
||||
return res.json({message: 'محصول با موفقیت حذف شد.'})
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
return res.json({message: v_m['fa'].response.success_remove})
|
||||
})
|
||||
}
|
||||
]
|
||||
@@ -381,15 +472,13 @@ module.exports.deleteProduct = [
|
||||
module.exports.createProductImage = [
|
||||
[
|
||||
body('product_id')
|
||||
.notEmpty().withMessage('مشخصات محصول را وارد کنید.')
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return Product.findById(value)
|
||||
.then(product => {
|
||||
return true
|
||||
})
|
||||
.catch(err => {
|
||||
return Promise.reject('محصولی با این مشخصات وجود ندارد.')
|
||||
return Promise.reject(v_m['fa'].not_found.item_id)
|
||||
})
|
||||
})
|
||||
],
|
||||
@@ -403,20 +492,17 @@ module.exports.createProductImage = [
|
||||
image = req.files.image
|
||||
imageName = 'productImages_' + Date.now() + '.' + image.mimetype.split('/')[1]
|
||||
|
||||
if (image.size / 1024 > 500) return res.status(422).json({validation: {images: {image: {msg: 'حجم عکس نباید بیشتر از 500 کیلوبایت باشد.'}}}})
|
||||
|
||||
|
||||
jimp.read(image.data)
|
||||
.then(img => {
|
||||
img
|
||||
.resize(250, jimp.AUTO)
|
||||
.cover(250, 250)
|
||||
.write(`./static/uploads/images/products/gallery/${imageName}`)
|
||||
.resize(470, jimp.AUTO)
|
||||
.cover(470, 390)
|
||||
.write(`./static/uploads/images/products/${imageName}`)
|
||||
|
||||
//// write to database
|
||||
Product.findById(req.body.product_id, (err, product) => {
|
||||
if (err) console.log(err)
|
||||
product.product_images.push({
|
||||
product.images.push({
|
||||
image: imageName,
|
||||
created_at: dateformat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
|
||||
})
|
||||
@@ -426,16 +512,16 @@ module.exports.createProductImage = [
|
||||
})
|
||||
|
||||
} else {
|
||||
return res.status(422).json({validation: {images: {image: {msg: 'عکس اجباری است.'}}}})
|
||||
return res.status(422).json({validation: {images: {image: {msg: v_m['fa'].required.image}}}})
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
module.exports.deleteProductImage = [
|
||||
(req, res) => {
|
||||
Product.findOne({'product_images._id': req.params.imageID}, (err, product) => {
|
||||
Product.findOne({'images._id': req.params.imageID}, (err, product) => {
|
||||
if (err) return res.status(404).json(err)
|
||||
const productImage = product.product_images.id(req.params.imageID)
|
||||
const productImage = product.images.id(req.params.imageID)
|
||||
fs.unlink(`./static/${productImage.image}`, err => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
@@ -449,85 +535,66 @@ module.exports.deleteProductImage = [
|
||||
]
|
||||
|
||||
////////////////////////////////////////// products features controllers
|
||||
module.exports.createProductFeature = [
|
||||
module.exports.createPDF = [
|
||||
[
|
||||
body('fa_name')
|
||||
.notEmpty().withMessage('عنوان نباید خالی باشد'),
|
||||
body('en_name')
|
||||
.notEmpty().withMessage('عنوان نباید خالی باشد'),
|
||||
body('de_name')
|
||||
.notEmpty().withMessage('عنوان نباید خالی باشد'),
|
||||
body('tr_name')
|
||||
.notEmpty().withMessage('عنوان نباید خالی باشد'),
|
||||
body('it_name')
|
||||
.notEmpty().withMessage('عنوان نباید خالی باشد'),
|
||||
|
||||
body('fa_value')
|
||||
.notEmpty().withMessage('توضیحات نباید خالی باشد'),
|
||||
body('en_value')
|
||||
.notEmpty().withMessage('توضیحات نباید خالی باشد'),
|
||||
body('tr_value')
|
||||
.notEmpty().withMessage('توضیحات نباید خالی باشد'),
|
||||
body('de_value')
|
||||
.notEmpty().withMessage('توضیحات نباید خالی باشد'),
|
||||
body('it_value')
|
||||
.notEmpty().withMessage('توضیحات نباید خالی باشد'),
|
||||
body('fa_pdf')
|
||||
.notEmpty().withMessage(v_m['fa'].required.title),
|
||||
body('en_pdf')
|
||||
.notEmpty().withMessage(v_m['fa'].required.title),
|
||||
|
||||
body('product_id')
|
||||
.notEmpty().withMessage('مشخصات محصول را وارد کنید.')
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return Product.findById(value)
|
||||
.then(product => {
|
||||
return true
|
||||
})
|
||||
.catch(err => {
|
||||
return Promise.reject('محصولی با این مشخصات وجود ندارد.')
|
||||
return Promise.reject(v_m['fa'].not_found.item_id)
|
||||
})
|
||||
})
|
||||
],
|
||||
(req, res) => {
|
||||
const errors = validationResult(req)
|
||||
if (!errors.isEmpty()) return res.status(422).json({validation: {features: errors.mapped()}})
|
||||
if (!errors.isEmpty()) return res.status(422).json({validation: errors.mapped()})
|
||||
if (!req.files || !req.files.pdf) return res.status(422).json({validation: {pdf: {msg: v_m['fa'].required.file}}})
|
||||
|
||||
let file = 'pdf_' + Date.now() + '.' + req.files.pdf.mimetype.split('/')[1]
|
||||
req.files.pdf.mv(`./static/uploads/pdf/${file}`, err => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
|
||||
const data = {
|
||||
fa: {
|
||||
name: req.body.fa_name,
|
||||
value: req.body.fa_value
|
||||
},
|
||||
en: {
|
||||
name: req.body.en_name,
|
||||
value: req.body.en_value
|
||||
},
|
||||
de: {
|
||||
name: req.body.de_name,
|
||||
value: req.body.de_value
|
||||
},
|
||||
tr: {
|
||||
name: req.body.tr_name,
|
||||
value: req.body.tr_value
|
||||
},
|
||||
it: {
|
||||
name: req.body.it_name,
|
||||
value: req.body.it_value
|
||||
file: file,
|
||||
pdf_details: {
|
||||
fa: {
|
||||
name: req.body.fa_pdf
|
||||
},
|
||||
en: {
|
||||
name: req.body.en_pdf
|
||||
}
|
||||
},
|
||||
created_at: dateformat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
|
||||
}
|
||||
|
||||
Product.findById(req.body.product_id, (err, product) => {
|
||||
if (err) console.log(err)
|
||||
product.product_features.push(data)
|
||||
product.pdf_files.push(data)
|
||||
product.save()
|
||||
return res.json(product)
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
module.exports.deleteProductFeature = [
|
||||
module.exports.deletePDF = [
|
||||
(req, res) => {
|
||||
Product.findOne({'product_features._id': req.params.featureID}, (err, product) => {
|
||||
Product.findOne({'pdf_files._id': req.params.pdfID}, (err, product) => {
|
||||
if (err) return res.status(500).json({message: err})
|
||||
product.product_features.id(req.params.featureID).remove()
|
||||
let pdf = product.pdf_files.id(req.params.pdfID)
|
||||
pdf.remove(cb => {
|
||||
fs.unlink(`./static/${pdf.file}`, err => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
})
|
||||
product.save()
|
||||
return res.json(product)
|
||||
})
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
const Project = require('../models/Project')
|
||||
const {body, validationResult} = require('express-validator')
|
||||
const jimp = require('jimp')
|
||||
const fs = require('fs')
|
||||
const dateFormat = require('dateformat')
|
||||
const v_m = require('../validation_messages')
|
||||
|
||||
///////////////////////////////////////// create project
|
||||
module.exports.create = [
|
||||
[
|
||||
body('fa_name')
|
||||
.notEmpty().withMessage(v_m['fa'].required.title)
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return Project.findOne({'project_details.fa.name': value})
|
||||
.then(project => {
|
||||
if (project) return Promise.reject(v_m['fa'].duplicated.name)
|
||||
else return true
|
||||
})
|
||||
}),
|
||||
|
||||
body('en_name')
|
||||
.notEmpty().withMessage(v_m['fa'].required.title)
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return Project.findOne({'project_details.en.name': value})
|
||||
.then(project => {
|
||||
if (project) return Promise.reject(v_m['fa'].duplicated.name)
|
||||
else return true
|
||||
})
|
||||
}),
|
||||
|
||||
body('date')
|
||||
.notEmpty().withMessage(v_m['fa'].required.date),
|
||||
],
|
||||
(req, res) => {
|
||||
const errors = validationResult(req)
|
||||
if (!errors.isEmpty()) return res.status(422).json({validation: errors.mapped()})
|
||||
|
||||
const data = {
|
||||
date: req.body.date,
|
||||
project_details: {
|
||||
fa: {
|
||||
name: req.body.fa_name,
|
||||
description: req.body.fa_description,
|
||||
},
|
||||
en: {
|
||||
name: req.body.en_name,
|
||||
description: req.body.en_description,
|
||||
}
|
||||
},
|
||||
created_at: dateFormat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
|
||||
}
|
||||
|
||||
const project = new Project(data)
|
||||
project.save((err, project) => {
|
||||
if (err) console.log(err)
|
||||
return res.json(project)
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
///////////////////////////////////////// get all projects
|
||||
module.exports.getAll = [
|
||||
(req, res) => {
|
||||
Project.find({}, (err, projects) => {
|
||||
if (err) return res.json({errors: err})
|
||||
return res.json(projects)
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
///////////////////////////////////////// get one project
|
||||
module.exports.getOne = [
|
||||
(req, res) => {
|
||||
Project.findById(req.params.id, (err, project) => {
|
||||
if (err) return res.json({errors: err})
|
||||
return res.json(project)
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
///////////////////////////////////////// update one project
|
||||
module.exports.update = [
|
||||
[
|
||||
body('fa_name')
|
||||
.notEmpty().withMessage(v_m['fa'].required.title)
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return Project.findOne({'project_details.fa.name': value})
|
||||
.then(project => {
|
||||
if (project && project._id.toString() !== req.params.id) return Promise.reject(v_m['fa'].duplicated.name)
|
||||
else return true
|
||||
})
|
||||
}),
|
||||
|
||||
body('en_name')
|
||||
.notEmpty().withMessage(v_m['fa'].required.title)
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
return Project.findOne({'project_details.en.name': value})
|
||||
.then(project => {
|
||||
if (project && project._id.toString() !== req.params.id) return Promise.reject(v_m['fa'].duplicated.name)
|
||||
else return true
|
||||
})
|
||||
}),
|
||||
|
||||
body('date')
|
||||
.notEmpty().withMessage(v_m['fa'].required.date),
|
||||
],
|
||||
(req, res) => {
|
||||
const errors = validationResult(req)
|
||||
if (!errors.isEmpty()) return res.status(422).json({validation: errors.mapped()})
|
||||
|
||||
const data = {
|
||||
date: req.body.date,
|
||||
project_details: {
|
||||
fa: {
|
||||
name: req.body.fa_name,
|
||||
description: req.body.fa_description,
|
||||
},
|
||||
en: {
|
||||
name: req.body.en_name,
|
||||
description: req.body.en_description,
|
||||
}
|
||||
},
|
||||
updated_at: dateFormat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
|
||||
}
|
||||
|
||||
Project.findByIdAndUpdate(req.params.id, data, (err, oldData) => {
|
||||
if (err) console.log(err)
|
||||
return res.json({message: v_m['fa'].response.success_save})
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
///////////////////////////////////////// delete project
|
||||
module.exports.delete = [
|
||||
(req, res) => {
|
||||
Project.findByIdAndRemove(req.params.id, (err, data) => {
|
||||
if (err) return res.json({error: err})
|
||||
data.images.forEach(async item => {
|
||||
await fs.unlink(`./static/${item.image}`, err => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
})
|
||||
return res.json({message: v_m['fa'].response.success_remove})
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/////////////////////////////// add images to project
|
||||
module.exports.addImage = [
|
||||
(req, res) => {
|
||||
Project.findById(req.params.id)
|
||||
.then(project => {
|
||||
if (!req.files || !req.files.image) return res.status(422).json({validation: {image: {msg: v_m['fa'].required.image}}})
|
||||
|
||||
let fileName = 'project_' + Date.now() + '.' + req.files.image.mimetype.split('/')[1]
|
||||
jimp.read(req.files.image.data)
|
||||
.then(img => {
|
||||
img
|
||||
.cover(1010, 534)
|
||||
.quality(80)
|
||||
.write(`./static/uploads/images/projects/${fileName}`)
|
||||
|
||||
////
|
||||
const data = {
|
||||
image: fileName,
|
||||
created_at: dateFormat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
|
||||
}
|
||||
project.images.push(data)
|
||||
project.save(cb => {
|
||||
return res.json(project)
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
module.exports.deleteImage = [
|
||||
(req, res) => {
|
||||
Project.findOne({'images._id': req.params.id}, (err, project) => {
|
||||
if (err) console.log(err)
|
||||
if (project) {
|
||||
let image = project.images.id(req.params.id)
|
||||
fs.unlink(`./static/${image.image}`, err => {
|
||||
if (err) console.log(err)
|
||||
image.remove()
|
||||
project.save(cb => {
|
||||
return res.json({message: v_m['fa'].response.success_remove})
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
]
|
||||
@@ -3,25 +3,22 @@ const dateFormat = require('dateformat')
|
||||
const {body, validationResult} = require('express-validator')
|
||||
const jimp = require('jimp')
|
||||
const fs = require('fs')
|
||||
|
||||
const v_m = require('../validation_messages')
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////// create
|
||||
module.exports.create = [
|
||||
[
|
||||
body('fa_title')
|
||||
.isLength({max: 40}).withMessage(v_m['fa'].max_char.max40),
|
||||
|
||||
body('en_title')
|
||||
.isLength({max: 40}).withMessage(v_m['fa'].max_char.max40),
|
||||
|
||||
body('fa_caption')
|
||||
.isLength({min: 10, max: 65}).withMessage('حداقل 10 کاراکتر و حداکثر 65 کاراکتر.'),
|
||||
.isLength({max: 100}).withMessage(v_m['fa'].max_char.max100),
|
||||
|
||||
body('en_caption')
|
||||
.isLength({min: 10, max: 65}).withMessage('حداقل 10 کاراکتر و حداکثر 65 کاراکتر.'),
|
||||
|
||||
body('de_caption')
|
||||
.isLength({min: 10, max: 65}).withMessage('حداقل 10 کاراکتر و حداکثر 65 کاراکتر.'),
|
||||
|
||||
body('tr_caption')
|
||||
.isLength({min: 10, max: 65}).withMessage('حداقل 10 کاراکتر و حداکثر 65 کاراکتر.'),
|
||||
|
||||
body('it_caption')
|
||||
.isLength({min: 10, max: 65}).withMessage('حداقل 10 کاراکتر و حداکثر 65 کاراکتر.')
|
||||
.isLength({max: 100}).withMessage(v_m['fa'].max_char.max100)
|
||||
],
|
||||
(req, res) => {
|
||||
const errors = validationResult(req)
|
||||
@@ -29,9 +26,9 @@ module.exports.create = [
|
||||
|
||||
if (req.files) {
|
||||
let file = req.files.image
|
||||
let fileName = 'image_' + Date.now() + '.' + file.mimetype.split('/')[1]
|
||||
jimp.read(file.data)
|
||||
.then(img => {
|
||||
let fileName = 'image_' + Date.now() + '.' + img.getExtension()
|
||||
if (img.bitmap.width >= 1920 && img.bitmap.height >= 1080) {
|
||||
if (file.size / 1024 < 450) {
|
||||
file.mv(`./static/uploads/images/slider/${fileName}`, (err, img) => {
|
||||
@@ -39,26 +36,19 @@ module.exports.create = [
|
||||
image: fileName,
|
||||
slider_details: {
|
||||
fa: {
|
||||
title: req.body.fa_title,
|
||||
caption: req.body.fa_caption
|
||||
},
|
||||
en: {
|
||||
title: req.body.en_title,
|
||||
caption: req.body.en_caption
|
||||
},
|
||||
de: {
|
||||
caption: req.body.de_caption
|
||||
},
|
||||
tr: {
|
||||
caption: req.body.tr_caption
|
||||
},
|
||||
it: {
|
||||
caption: req.body.it_caption
|
||||
}
|
||||
},
|
||||
created_at: dateFormat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
|
||||
})
|
||||
slider.save((err, data) => {
|
||||
if (err) return res.status(500).json({error: err})
|
||||
return res.json({message: 'اسلاید اضافه شد'})
|
||||
return res.json({message: v_m['fa'].response.success_save})
|
||||
})
|
||||
})
|
||||
} else {
|
||||
@@ -72,7 +62,7 @@ module.exports.create = [
|
||||
console.log(err)
|
||||
})
|
||||
} else {
|
||||
return res.status(422).json({validation: {image: {msg: 'عکس اجباری است.'}}})
|
||||
return res.status(422).json({validation: {image: {msg: v_m['fa'].required.image}}})
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -91,7 +81,7 @@ module.exports.getAll = [
|
||||
module.exports.getOne = [
|
||||
(req, res) => {
|
||||
Slider.findById(req.params.id, (err, slide) => {
|
||||
if (err) return res.status(404).json({error: 'no slide with this id.'})
|
||||
if (err) return res.status(404).json({error: v_m['fa'].not_found.item_id})
|
||||
return res.json(slide)
|
||||
})
|
||||
}
|
||||
@@ -100,20 +90,17 @@ module.exports.getOne = [
|
||||
//////////////////////////////////////////////////////////////////////////////// update
|
||||
module.exports.update = [
|
||||
[
|
||||
body('fa_title')
|
||||
.isLength({max: 40}).withMessage(v_m['fa'].max_char.max40),
|
||||
|
||||
body('en_title')
|
||||
.isLength({max: 40}).withMessage(v_m['fa'].max_char.max40),
|
||||
|
||||
body('fa_caption')
|
||||
.isLength({min: 10, max: 65}).withMessage('حداقل 10 کاراکتر و حداکثر 65 کاراکتر.'),
|
||||
.isLength({max: 100}).withMessage(v_m['fa'].max_char.max100),
|
||||
|
||||
body('en_caption')
|
||||
.isLength({min: 10, max: 65}).withMessage('حداقل 10 کاراکتر و حداکثر 65 کاراکتر.'),
|
||||
|
||||
body('de_caption')
|
||||
.isLength({min: 10, max: 65}).withMessage('حداقل 10 کاراکتر و حداکثر 65 کاراکتر.'),
|
||||
|
||||
body('tr_caption')
|
||||
.isLength({min: 10, max: 65}).withMessage('حداقل 10 کاراکتر و حداکثر 65 کاراکتر.'),
|
||||
|
||||
body('it_caption')
|
||||
.isLength({min: 10, max: 65}).withMessage('حداقل 10 کاراکتر و حداکثر 65 کاراکتر.')
|
||||
.isLength({max: 100}).withMessage(v_m['fa'].max_char.max100)
|
||||
],
|
||||
(req, res) => {
|
||||
const errors = validationResult(req)
|
||||
@@ -122,19 +109,12 @@ module.exports.update = [
|
||||
const data = {
|
||||
slider_details: {
|
||||
fa: {
|
||||
title: req.body.fa_title,
|
||||
caption: req.body.fa_caption
|
||||
},
|
||||
en: {
|
||||
title: req.body.en_title,
|
||||
caption: req.body.en_caption
|
||||
},
|
||||
de: {
|
||||
caption: req.body.de_caption
|
||||
},
|
||||
tr: {
|
||||
caption: req.body.tr_caption
|
||||
},
|
||||
it: {
|
||||
caption: req.body.it_caption
|
||||
}
|
||||
},
|
||||
updated_at: dateFormat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
|
||||
@@ -142,12 +122,10 @@ module.exports.update = [
|
||||
|
||||
if (req.files) {
|
||||
let file = req.files.image
|
||||
let fileName = 'image_' + Date.now() + '.' + file.mimetype.split('/')[1]
|
||||
|
||||
data.image = fileName
|
||||
|
||||
jimp.read(file.data)
|
||||
.then(img => {
|
||||
let fileName = 'image_' + Date.now() + '.' + img.getExtension()
|
||||
data.image = fileName
|
||||
if (img.bitmap.width >= 1920 && img.bitmap.height >= 1080) {
|
||||
if (file.size / 1024 < 450) {
|
||||
file.mv(`./static/uploads/images/slider/${fileName}`, (err) => {
|
||||
@@ -158,7 +136,7 @@ module.exports.update = [
|
||||
fs.unlink(`./static/${oldSlide.image}`, err => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
return res.json({message: 'اسلاید آپدیت شد.'})
|
||||
return res.json({message: v_m['fa'].response.success_save})
|
||||
})
|
||||
})
|
||||
} else {
|
||||
@@ -175,7 +153,7 @@ module.exports.update = [
|
||||
} else {
|
||||
Slider.findByIdAndUpdate(req.params.id, data, (err, oldSlide) => {
|
||||
if (err) return res.status(500).json({error: err})
|
||||
return res.json({message: 'اسلاید آپدیت شد.'})
|
||||
return res.json({message: v_m['fa'].response.success_save})
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -189,7 +167,7 @@ module.exports.delete = [
|
||||
fs.unlink(`./static/${data.image}`, err => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
return res.json({message: 'اسلاید حذف شد'})
|
||||
return res.json({message: v_m['fa'].response.success_remove})
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,689 +0,0 @@
|
||||
const User = require('../models/user/User')
|
||||
const v_m = require('../validation_messages')
|
||||
const {body, validationResult} = require('express-validator')
|
||||
const dateformat = require('dateformat')
|
||||
const bcrypt = require('bcryptjs')
|
||||
const crypto = require('crypto')
|
||||
const jwt = require('jsonwebtoken')
|
||||
const config = require('../config')
|
||||
const nodemailer = require('nodemailer')
|
||||
|
||||
/////////////////////////////////////////////////////////////////////// register
|
||||
module.exports.register = [
|
||||
[
|
||||
body('first_name')
|
||||
.notEmpty()
|
||||
.withMessage((value, {req}) => {
|
||||
return v_m[req.body.locale].required.first_name
|
||||
})
|
||||
.bail()
|
||||
.isLength({min: 2})
|
||||
.withMessage((value, {req}) => {
|
||||
return v_m[req.body.locale].min_char.min2
|
||||
}),
|
||||
|
||||
body('last_name')
|
||||
.notEmpty()
|
||||
.withMessage((value, {req}) => {
|
||||
return v_m[req.body.locale].required.last_name
|
||||
})
|
||||
.bail()
|
||||
.isLength({min: 2})
|
||||
.withMessage((value, {req}) => {
|
||||
return v_m[req.body.locale].min_char.min2
|
||||
}),
|
||||
|
||||
body('company_name')
|
||||
.if((value, {req}) => req.body.type === 'company')
|
||||
.notEmpty()
|
||||
.withMessage((value, {req}) => {
|
||||
return v_m[req.body.locale].required.company_name
|
||||
}),
|
||||
|
||||
body('email_personal')
|
||||
.if((value, {req}) => req.body.type === 'personal')
|
||||
.notEmpty()
|
||||
.withMessage((value, {req}) => {
|
||||
return v_m[req.body.locale].required.email_personal
|
||||
}),
|
||||
|
||||
body('email_personal')
|
||||
.if(body('email_personal').notEmpty())
|
||||
.isEmail()
|
||||
.withMessage((value, {req}) => {
|
||||
return v_m[req.body.locale].format.email
|
||||
})
|
||||
.custom((value, {req}) => {
|
||||
return User.findOne({$or: [{email_personal: value}, {email_company: value}]})
|
||||
.then(user => {
|
||||
if (user) return Promise.reject(v_m[req.body.locale].duplicated.email)
|
||||
else return true
|
||||
})
|
||||
}),
|
||||
|
||||
body('email_company')
|
||||
.if((value, {req}) => req.body.type === 'company')
|
||||
.notEmpty()
|
||||
.withMessage((value, {req}) => {
|
||||
return v_m[req.body.locale].required.email_company
|
||||
})
|
||||
.bail()
|
||||
.isEmail()
|
||||
.withMessage((value, {req}) => {
|
||||
return v_m[req.body.locale].format.email
|
||||
})
|
||||
.custom((value, {req}) => {
|
||||
return User.findOne({$or: [{email_personal: value}, {email_company: value}]})
|
||||
.then(user => {
|
||||
if (user) return Promise.reject(v_m[req.body.locale].duplicated.email)
|
||||
else return true
|
||||
})
|
||||
}),
|
||||
|
||||
body('password')
|
||||
.isLength({min: 4})
|
||||
.withMessage((value, {req}) => {
|
||||
return v_m[req.body.locale].min_char.min4
|
||||
}),
|
||||
|
||||
body('phone_number')
|
||||
.isNumeric()
|
||||
.withMessage((value, {req}) => {
|
||||
return v_m[req.body.locale].format.phone_number
|
||||
}),
|
||||
|
||||
body('password_confirmation')
|
||||
.isLength({min: 4})
|
||||
.withMessage((value, {req}) => {
|
||||
return v_m[req.body.locale].min_char.min4
|
||||
})
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
if (value !== req.body.password) return Promise.reject(v_m[req.body.locale].required.password_confirmation)
|
||||
else return true
|
||||
})
|
||||
],
|
||||
(req, res) => {
|
||||
const errors = validationResult(req)
|
||||
if (!errors.isEmpty()) return res.status(422).json({validation: errors.mapped()})
|
||||
|
||||
const data = {}
|
||||
data.first_name = req.body.first_name
|
||||
data.last_name = req.body.last_name
|
||||
data.type = req.body.type
|
||||
data.company_name = req.body.company_name
|
||||
data.email_personal = req.body.email_personal
|
||||
data.email_company = req.body.email_company
|
||||
data.fb_id_personal = req.body.fb_id_personal
|
||||
data.fb_id_company = req.body.fb_id_company
|
||||
data.ig_id_personal = req.body.ig_id_personal
|
||||
data.ig_id_company = req.body.ig_id_company
|
||||
data.skype_id_personal = req.body.skype_id_personal
|
||||
data.skype_id_company = req.body.skype_id_company
|
||||
data.phone_number = req.body.phone_number
|
||||
data.scope = 'user'
|
||||
data.created_at = dateformat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
|
||||
|
||||
|
||||
// generate activation key
|
||||
let confirmation_key
|
||||
crypto.randomBytes(20, async (err, hash) => {
|
||||
if (err) console.log(err)
|
||||
confirmation_key = hash.toString('hex')
|
||||
data.confirmation_key = confirmation_key
|
||||
|
||||
let transporter = nodemailer.createTransport({
|
||||
host: "www.rubynaturalco.com",
|
||||
port: 587,
|
||||
secure: false, // true for 465, false for other ports
|
||||
auth: {
|
||||
user: 'recovery@rubynaturalco.com',
|
||||
pass: 'jd-m2?3ao?b('
|
||||
},
|
||||
tls: {
|
||||
rejectUnauthorized: false
|
||||
}
|
||||
})
|
||||
|
||||
// send mail with defined transport object
|
||||
let info = await transporter.sendMail({
|
||||
from: '"Hima Co." <recovery@rubynaturalco.com>', // sender address
|
||||
to: req.body.type === 'personal' ? req.body.email_personal : req.body.email_company, // list of receivers
|
||||
subject: "Activation Link",
|
||||
text: 'Active your account',
|
||||
html: `
|
||||
<h1>You just registered an account on <b style="color: #784fae;">Hima Website</b></h1>
|
||||
<p>to activate your account click link below:</p>
|
||||
<a href="https://www.rubynaturalco.com/en/account/activation/${confirmation_key}"
|
||||
target="_blank"
|
||||
style="display: inline-block;font-family: sans-serif;padding: 15px;background: #784fae;color: #fff;border-radius: 5px;margin-top: 20px;">Active Account</a>
|
||||
`
|
||||
})
|
||||
|
||||
// hash user password and done
|
||||
bcrypt.genSalt(10, (err, salt) => {
|
||||
bcrypt.hash(req.body.password, salt, (err, hash) => {
|
||||
if (err) console.log(err)
|
||||
data.password = hash
|
||||
|
||||
const user = new User(data)
|
||||
user.save(err => {
|
||||
if (err) console.log(err)
|
||||
return res.json({message: v_m[req.body.locale].response.success_save})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
/////////////////////////////////////////////////////////////////////// active user
|
||||
module.exports.activation = [
|
||||
(req, res) => {
|
||||
User.findOne({confirmation_key: req.params.key})
|
||||
.then(user => {
|
||||
if (user) {
|
||||
user.confirmation_key = null
|
||||
user.confirmed = true
|
||||
user.save(err => {
|
||||
if (err) console.log(err)
|
||||
return res.json({message: v_m[req.body.locale].response.success_activation})
|
||||
})
|
||||
} else {
|
||||
return res.status(404).json({message: v_m[req.body.locale].response.expired_activation_link})
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
return res.status(500).json(err)
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
/////////////////////////////////////////////////////////////////////// login
|
||||
module.exports.login = [
|
||||
[
|
||||
body('email')
|
||||
.notEmpty()
|
||||
.withMessage((value, {req}) => {
|
||||
return v_m[req.body.locale].required.email
|
||||
})
|
||||
.custom((value, {req}) => {
|
||||
return User.findOne({$or: [{email_personal: value}, {email_company: value}]})
|
||||
.then(user => {
|
||||
if (!user) return Promise.reject(v_m[req.body.locale].not_found.user_id)
|
||||
else return true
|
||||
})
|
||||
}),
|
||||
|
||||
body('password')
|
||||
.notEmpty()
|
||||
.withMessage((value, {req}) => {
|
||||
return v_m[req.body.locale].required.password
|
||||
}),
|
||||
|
||||
body('remember_me')
|
||||
.exists()
|
||||
.withMessage((value, {req}) => {
|
||||
return v_m[req.body.locale].required.remember_me
|
||||
})
|
||||
.bail()
|
||||
.isBoolean()
|
||||
.withMessage((value, {req}) => {
|
||||
return v_m[req.body.locale].format.boolean
|
||||
})
|
||||
],
|
||||
(req, res) => {
|
||||
const errors = validationResult(req)
|
||||
if (!errors.isEmpty()) return res.status(422).json({validation: errors.mapped()})
|
||||
|
||||
|
||||
User.findOne({$or: [{email_personal: req.body.email}, {email_company: req.body.email}]}, (err, user) => {
|
||||
if (err) console.log(err)
|
||||
if (!user.confirmed) return res.status(401).json({message: v_m[req.body.locale].response.email_not_confirmed})
|
||||
bcrypt.compare(req.body.password, user.password, (err, isMatch) => {
|
||||
if (err) console.log(err)
|
||||
if (!isMatch) return res.status(422).json({validation: {password: {msg: v_m[req.body.locale].not_found.password}}})
|
||||
let token
|
||||
if (req.body.remember_me) token = jwt.sign({_id: user._id}, config.secretKey)
|
||||
else token = jwt.sign({_id: user._id}, config.secretKey, {expiresIn: '1h'})
|
||||
|
||||
user.token = token
|
||||
user.reset_pass_key = null
|
||||
user.save(err => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
return res.json({token: token})
|
||||
})
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
/////////////////////////////////////////////////////////////////////// logout
|
||||
module.exports.logout = [
|
||||
(req, res) => {
|
||||
const token = req.headers.authorization
|
||||
if (token) {
|
||||
User.findOneAndUpdate({token: token}, {token: null}, (err, oldData) => {
|
||||
if (err) console.log(err)
|
||||
if (oldData) return res.json({message: v_m['en'].response.logged_out})
|
||||
return res.status(401).json({message: v_m['en'].response.not_logged_in})
|
||||
})
|
||||
} else {
|
||||
return res.status(401).json({message: v_m['en'].response.not_logged_in})
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
/////////////////////////////////////////////////////////////////////// get user
|
||||
module.exports.getUser = [
|
||||
config.isUser,
|
||||
(req, res) => {
|
||||
const token = req.headers.authorization
|
||||
if (token) {
|
||||
jwt.verify(token, config.secretKey, (err, decoded) => {
|
||||
if (err) return res.status(401).json({message: v_m['en'].response.unauthenticated})
|
||||
User.findById(decoded._id).select('-password -reset_pass_key -token -confirmed -confirmation_key').exec((err, data) => {
|
||||
if (err) console.log(err)
|
||||
return res.json({user: data})
|
||||
})
|
||||
})
|
||||
} else {
|
||||
return res.status(401).json({message: v_m['en'].response.unauthenticated})
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
/////////////////////////////////////////////////////////////////////// reset password key generator
|
||||
module.exports.resetPassKey = [
|
||||
[
|
||||
body('email')
|
||||
.notEmpty()
|
||||
.withMessage((value, {req}) => {
|
||||
return v_m[req.body.locale].required.email
|
||||
})
|
||||
.bail()
|
||||
.isEmail()
|
||||
.withMessage((value, {req}) => {
|
||||
return v_m[req.body.locale].format.email
|
||||
})
|
||||
],
|
||||
(req, res) => {
|
||||
const errors = validationResult(req)
|
||||
if (!errors.isEmpty()) return res.status(422).json({validation: errors.mapped()})
|
||||
|
||||
User.findOne({$or: [{email_personal: req.body.email}, {email_company: req.body.email}]})
|
||||
.then(user => {
|
||||
if (user) {
|
||||
let pass_token
|
||||
crypto.randomBytes(20, async (err, hash) => {
|
||||
if (err) console.log(err)
|
||||
pass_token = hash.toString('hex')
|
||||
user.reset_pass_key = pass_token
|
||||
await user.save(err => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
|
||||
let transporter = nodemailer.createTransport({
|
||||
host: "www.rubynaturalco.com",
|
||||
port: 587,
|
||||
secure: false, // true for 465, false for other ports
|
||||
auth: {
|
||||
user: 'recovery@rubynaturalco.com',
|
||||
pass: 'jd-m2?3ao?b('
|
||||
},
|
||||
tls: {
|
||||
rejectUnauthorized: false
|
||||
}
|
||||
})
|
||||
|
||||
// send mail with defined transport object
|
||||
let info = await transporter.sendMail({
|
||||
from: '"Hima Co." <recovery@rubynaturalco.com>', // sender address
|
||||
to: req.body.email, // list of receivers
|
||||
subject: "Reset Password Link",
|
||||
text: 'Reset your password',
|
||||
html: `
|
||||
<h1>You asked to reset your account password on <b style="color: #784fae;">Hima Website</b></h1>
|
||||
<p>to reset your password click on link blow, then enter new password:</p>
|
||||
<a href="https://www.rubynaturalco.com/en/account/new-password/${pass_token}"
|
||||
target="_blank"
|
||||
style="display: inline-block;font-family: sans-serif;padding: 15px;background: #784fae;color: #fff;border-radius: 5px;margin-top: 20px;">Reset Password</a>
|
||||
`
|
||||
})
|
||||
|
||||
// Message sent: <b658f8ca-6296-ccf4-8306-87d57a0b4321@example.com>
|
||||
return res.json({message: v_m[req.body.locale].response.recovery_link})
|
||||
})
|
||||
} else {
|
||||
return res.status(404).json({message: v_m[req.body.locale].not_found.user_id})
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
return res.status(500).json(err)
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
/////////////////////////////////////////////////////////////////////// set new password
|
||||
module.exports.setNewPass = [
|
||||
[
|
||||
body('password')
|
||||
.isLength({min: 4})
|
||||
.withMessage((value, {req}) => {
|
||||
return v_m[req.body.locale].min_char.min4
|
||||
})
|
||||
,
|
||||
|
||||
body('password_confirmation')
|
||||
.isLength({min: 4})
|
||||
.withMessage((value, {req}) => {
|
||||
return v_m[req.body.locale].min_char.min4
|
||||
})
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
if (value !== req.body.password) return Promise.reject(v_m[req.body.locale].required.password_confirmation)
|
||||
else return true
|
||||
})
|
||||
],
|
||||
(req, res) => {
|
||||
const errors = validationResult(req)
|
||||
if (!errors.isEmpty()) return res.status(422).json({validation: errors.mapped()})
|
||||
|
||||
User.findOne({reset_pass_key: req.params.key})
|
||||
.then(user => {
|
||||
if (user) {
|
||||
bcrypt.genSalt(10, (err, salt) => {
|
||||
bcrypt.hash(req.body.password, salt, (err, hash) => {
|
||||
if (err) console.log(err)
|
||||
user.password = hash
|
||||
user.reset_pass_key = null
|
||||
user.save(err => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
return res.json({message: v_m[req.body.locale].response.success_save})
|
||||
})
|
||||
})
|
||||
} else {
|
||||
return res.status(404).json({message: v_m[req.body.locale].response.expired_reset_link})
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
return res.status(500).json(err)
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
/////////////////////////////////////////////////////////////////////// update user
|
||||
module.exports.updateUser = [
|
||||
[
|
||||
body('first_name')
|
||||
.isLength({min: 2})
|
||||
.withMessage((value, {req}) => {
|
||||
return v_m[req.body.locale].min_char.min2
|
||||
}),
|
||||
|
||||
body('last_name')
|
||||
.isLength({min: 2})
|
||||
.withMessage((value, {req}) => {
|
||||
return v_m[req.body.locale].min_char.min2
|
||||
}),
|
||||
|
||||
body('email_personal')
|
||||
.if((value, {req}) => req.body.type === 'personal')
|
||||
.notEmpty()
|
||||
.withMessage((value, {req}) => {
|
||||
return v_m[req.body.locale].required.email_personal
|
||||
}),
|
||||
|
||||
body('email_personal')
|
||||
.if(body('email_personal').notEmpty())
|
||||
.isEmail()
|
||||
.withMessage((value, {req}) => {
|
||||
return v_m[req.body.locale].format.email
|
||||
}),
|
||||
|
||||
body('phone_number')
|
||||
.isNumeric()
|
||||
.withMessage((value, {req}) => {
|
||||
return v_m[req.body.locale].format.phone_number
|
||||
}),
|
||||
|
||||
body('email_company')
|
||||
.if((value, {req}) => req.body.type === 'company')
|
||||
.notEmpty()
|
||||
.withMessage((value, {req}) => {
|
||||
return v_m[req.body.locale].required.email_company
|
||||
})
|
||||
.bail()
|
||||
.isEmail()
|
||||
.withMessage((value, {req}) => {
|
||||
return v_m[req.body.locale].format.email
|
||||
}),
|
||||
],
|
||||
(req, res) => {
|
||||
const errors = validationResult(req)
|
||||
if (!errors.isEmpty()) return res.status(422).json({validation: errors.mapped()})
|
||||
|
||||
const token = req.headers.authorization
|
||||
const data = {}
|
||||
data.first_name = req.body.first_name
|
||||
data.last_name = req.body.last_name
|
||||
data.email_personal = req.body.email_personal
|
||||
data.fb_id_personal = req.body.fb_id_personal
|
||||
data.ig_id_personal = req.body.ig_id_personal
|
||||
data.skype_id_personal = req.body.skype_id_personal
|
||||
data.phone_number = req.body.phone_number
|
||||
data.updated_at = dateformat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
|
||||
|
||||
if (req.body.type === 'company') {
|
||||
data.skype_id_company = req.body.skype_id_company
|
||||
data.ig_id_company = req.body.ig_id_company
|
||||
data.fb_id_company = req.body.fb_id_company
|
||||
data.email_company = req.body.email_company
|
||||
data.company_name = req.body.company_name
|
||||
}
|
||||
User.findOneAndUpdate({token: token}, data)
|
||||
.then(user => {
|
||||
return res.json({message: v_m[req.body.locale].response.success_save})
|
||||
})
|
||||
.catch(err => {
|
||||
return res.status(401).json({message: v_m[req.body.locale].response.unauthenticated})
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
/////////////////////////////////////////////////////////////////////// update user password
|
||||
module.exports.updateUserPassword = [
|
||||
[
|
||||
body('password')
|
||||
.isLength({min: 4})
|
||||
.withMessage((value, {req}) => {
|
||||
return v_m[req.body.locale].min_char.min4
|
||||
}),
|
||||
|
||||
body('password_confirmation')
|
||||
.isLength({min: 4})
|
||||
.withMessage((value, {req}) => {
|
||||
return v_m[req.body.locale].min_char.min4
|
||||
})
|
||||
.bail()
|
||||
.custom((value, {req}) => {
|
||||
if (value !== req.body.password) return Promise.reject(v_m[req.body.locale].required.password_confirmation)
|
||||
else return true
|
||||
})
|
||||
],
|
||||
(req, res) => {
|
||||
const errors = validationResult(req)
|
||||
if (!errors.isEmpty()) return res.status(422).json({validation: errors.mapped()})
|
||||
|
||||
const token = req.headers.authorization
|
||||
User.findOne({token: token})
|
||||
.then(user => {
|
||||
bcrypt.genSalt(10, (err, salt) => {
|
||||
if (err) console.log(err)
|
||||
bcrypt.hash(req.body.password, salt, (err, hash) => {
|
||||
if (err) console.log(err)
|
||||
user.password = hash
|
||||
user.token = null
|
||||
user.save(err => {
|
||||
if (err) console.log(err)
|
||||
return res.json({message: v_m[req.body.locale].response.success_save})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
return res.status(404).json(err)
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
/////////////////////////////////////////////////////////////////////// addresses
|
||||
module.exports.addAdress = [
|
||||
[
|
||||
body('user_id')
|
||||
.custom((value, {req}) => {
|
||||
return User.findById(value)
|
||||
.then(user => {
|
||||
return true
|
||||
})
|
||||
.catch(err => {
|
||||
return Promise.reject(v_m[req.body.locale].not_found.user_id)
|
||||
})
|
||||
}),
|
||||
|
||||
body('country')
|
||||
.if(body('country').isEmpty())
|
||||
.custom((value, {req}) => {
|
||||
return Promise.reject(v_m[req.body.locale].required.country)
|
||||
}),
|
||||
|
||||
body('province')
|
||||
.if(body('province').isEmpty())
|
||||
.custom((value, {req}) => {
|
||||
return Promise.reject(v_m[req.body.locale].required.province)
|
||||
}),
|
||||
|
||||
body('city')
|
||||
.if(body('city').isEmpty())
|
||||
.custom((value, {req}) => {
|
||||
return Promise.reject(v_m[req.body.locale].required.city)
|
||||
}),
|
||||
|
||||
body('address')
|
||||
.if(body('address').isEmpty())
|
||||
.custom((value, {req}) => {
|
||||
return Promise.reject(v_m[req.body.locale].required.address)
|
||||
}),
|
||||
|
||||
body('postal_code')
|
||||
.if(body('postal_code').isEmpty())
|
||||
.custom((value, {req}) => {
|
||||
return Promise.reject(v_m[req.body.locale].required.postal_code)
|
||||
}),
|
||||
|
||||
body('plaque')
|
||||
.if(body('plaque').isEmpty())
|
||||
.custom((value, {req}) => {
|
||||
return Promise.reject(v_m[req.body.locale].required.plaque)
|
||||
}),
|
||||
|
||||
body('receiver_first_name')
|
||||
.if(body('receiver_first_name').isEmpty())
|
||||
.custom((value, {req}) => {
|
||||
return Promise.reject(v_m[req.body.locale].required.receiver_first_name)
|
||||
}),
|
||||
|
||||
body('receiver_last_name')
|
||||
.if(body('receiver_last_name').isEmpty())
|
||||
.custom((value, {req}) => {
|
||||
return Promise.reject(v_m[req.body.locale].required.receiver_last_name)
|
||||
}),
|
||||
|
||||
body('receiver_mobile')
|
||||
.if(body('receiver_mobile').isEmpty())
|
||||
.custom((value, {req}) => {
|
||||
return Promise.reject(v_m[req.body.locale].required.receiver_mobile)
|
||||
}),
|
||||
|
||||
body('receiver_mobile')
|
||||
.if(body('receiver_mobile').notEmpty())
|
||||
.if(body('receiver_mobile').not().isNumeric())
|
||||
.custom((value, {req}) => {
|
||||
return Promise.reject(v_m[req.body.locale].format.phone_number)
|
||||
})
|
||||
],
|
||||
(req, res) => {
|
||||
const errors = validationResult(req)
|
||||
if (!errors.isEmpty()) return res.status(422).json({validation: errors.mapped()})
|
||||
|
||||
const data = {
|
||||
country: req.body.country,
|
||||
province: req.body.province,
|
||||
city: req.body.city,
|
||||
address: req.body.address,
|
||||
postal_code: req.body.postal_code,
|
||||
plaque: req.body.plaque,
|
||||
block_number: req.body.block_number,
|
||||
receiver_first_name: req.body.receiver_first_name,
|
||||
receiver_last_name: req.body.receiver_last_name,
|
||||
receiver_mobile: req.body.receiver_mobile,
|
||||
created_at: dateformat(Date.now(), 'yyyy-mm-dd HH:MM:ss')
|
||||
}
|
||||
|
||||
User.findById(req.body.user_id)
|
||||
.then(user => {
|
||||
user.addresses.push(data)
|
||||
user.save()
|
||||
return res.json(user.addresses)
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
module.exports.getAddresses = [
|
||||
(req, res) => {
|
||||
User.findById(req.params.user_id)
|
||||
.then(user => {
|
||||
return res.json(user.addresses)
|
||||
})
|
||||
.catch(err => {
|
||||
return res.status(404).json({message: v_m['en'].not_found.user_id})
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
module.exports.deleteAddress = [
|
||||
(req, res) => {
|
||||
User.findOne({'addresses._id': req.params.address_id})
|
||||
.then(user => {
|
||||
user.addresses.id(req.params.address_id).remove()
|
||||
user.save()
|
||||
return res.json({message: v_m['en'].response.success_remove})
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
/////////////////////////////////////////////////////////////////////// get list of users by admin
|
||||
module.exports.getAllUsers = [
|
||||
(req, res) => {
|
||||
User.find({confirmed: true}).select('-token -password -scope -reset_pass_key -confirmed -confirmation_key').exec((err, users) => {
|
||||
if (err) console.log(err)
|
||||
return res.json(users)
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
module.exports.getOneUser = [
|
||||
(req, res) => {
|
||||
User.findById(req.params.user_id).select('-token -password -scope -reset_pass_key -confirmed -confirmation_key').exec((err, user) => {
|
||||
if (err) return res.status(404).json(err)
|
||||
return res.json(user)
|
||||
})
|
||||
}
|
||||
]
|
||||
@@ -1,6 +1,6 @@
|
||||
const mongoose = require('mongoose');
|
||||
// mongodb database connection string. change it as per your needs. here "mydb" is the name of the database. You don't need to create DB from mongodb terminal. mongoose create the db automatically.
|
||||
mongoose.connect('mongodb://localhost:27017/hima', {
|
||||
mongoose.connect('mongodb://localhost:27017/arakrail', {
|
||||
useNewUrlParser: true,
|
||||
useUnifiedTopology: true,
|
||||
useFindAndModify: false,
|
||||
|
||||
@@ -2,7 +2,6 @@ const express = require('express')
|
||||
const db = require('./db')
|
||||
const fileUpload = require('express-fileupload')
|
||||
const config = require('./config')
|
||||
const cron_jobs = require('./cron_jobs')
|
||||
|
||||
// Create express instnace
|
||||
const app = express()
|
||||
@@ -15,17 +14,13 @@ app.use(fileUpload())
|
||||
// Require & Import API routes
|
||||
const Private = require('./routes/private')
|
||||
const Public = require('./routes/public')
|
||||
const user = require('./routes/user')
|
||||
const auth = require('./routes/auth')
|
||||
|
||||
// Use API Routes
|
||||
app.use('/private', config.isAdmin, Private)
|
||||
app.use('/user', config.isUser, user)
|
||||
app.use('/auth', auth)
|
||||
app.use('/public', Public)
|
||||
|
||||
// add cron jobs checker
|
||||
cron_jobs()
|
||||
|
||||
// Export the server middleware
|
||||
module.exports = {
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
const mongoose = require('mongoose')
|
||||
|
||||
function image(img) {
|
||||
return '/uploads/images/about/' + img
|
||||
}
|
||||
|
||||
const AboutPageSchema = mongoose.Schema({
|
||||
aboutPage_details: {
|
||||
fa: {
|
||||
page_title: String,
|
||||
s1_title: String,
|
||||
s1_caption: String,
|
||||
s2_title: String,
|
||||
s2_caption: String,
|
||||
s2_imageCaption: String,
|
||||
s3_title: String,
|
||||
s3_caption: String,
|
||||
s3_imageCaption: String,
|
||||
s4_text: String,
|
||||
last_section_title: String,
|
||||
last_section_text: String
|
||||
},
|
||||
en: {
|
||||
page_title: String,
|
||||
s1_title: String,
|
||||
s1_caption: String,
|
||||
s2_title: String,
|
||||
s2_caption: String,
|
||||
s2_imageCaption: String,
|
||||
s3_title: String,
|
||||
s3_caption: String,
|
||||
s3_imageCaption: String,
|
||||
s4_text: String,
|
||||
last_section_title: String,
|
||||
last_section_text: String
|
||||
},
|
||||
de: {
|
||||
page_title: String,
|
||||
s1_title: String,
|
||||
s1_caption: String,
|
||||
s2_title: String,
|
||||
s2_caption: String,
|
||||
s2_imageCaption: String,
|
||||
s3_title: String,
|
||||
s3_caption: String,
|
||||
s3_imageCaption: String,
|
||||
s4_text: String,
|
||||
last_section_title: String,
|
||||
last_section_text: String
|
||||
},
|
||||
tr: {
|
||||
page_title: String,
|
||||
s1_title: String,
|
||||
s1_caption: String,
|
||||
s2_title: String,
|
||||
s2_caption: String,
|
||||
s2_imageCaption: String,
|
||||
s3_title: String,
|
||||
s3_caption: String,
|
||||
s3_imageCaption: String,
|
||||
s4_text: String,
|
||||
last_section_title: String,
|
||||
last_section_text: String
|
||||
},
|
||||
it: {
|
||||
page_title: String,
|
||||
s1_title: String,
|
||||
s1_caption: String,
|
||||
s2_title: String,
|
||||
s2_caption: String,
|
||||
s2_imageCaption: String,
|
||||
s3_title: String,
|
||||
s3_caption: String,
|
||||
s3_imageCaption: String,
|
||||
s4_text: String,
|
||||
last_section_title: String,
|
||||
last_section_text: String
|
||||
}
|
||||
},
|
||||
page_hero: {type: String, get: image},
|
||||
s2_image: {type: String, get: image},
|
||||
s3_image: {type: String, get: image},
|
||||
last_section_image: {type: String, get: image},
|
||||
created_at: String,
|
||||
updated_at: String
|
||||
}, {
|
||||
toObject: {getters: true},
|
||||
toJSON: {getters: true}
|
||||
})
|
||||
|
||||
|
||||
module.exports = mongoose.model('AboutPageContent', AboutPageSchema)
|
||||
@@ -1,13 +0,0 @@
|
||||
const mongoose = require('mongoose')
|
||||
|
||||
const BroadcastSchema = mongoose.Schema({
|
||||
title: String,
|
||||
message: String,
|
||||
read: Array,
|
||||
locale: String,
|
||||
admin_id: String,
|
||||
created_at: String
|
||||
})
|
||||
|
||||
|
||||
module.exports = mongoose.model('Broadcast', BroadcastSchema)
|
||||
@@ -6,7 +6,7 @@ const ContactPageMessageSchema = mongoose.Schema({
|
||||
phone_number: String,
|
||||
email: String,
|
||||
message: String,
|
||||
user_id: String,
|
||||
reason: String,
|
||||
read: {type: Boolean, default: false},
|
||||
created_at: String
|
||||
})
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
const mongoose = require('mongoose')
|
||||
|
||||
const ReasonSchema = mongoose.Schema({
|
||||
reason_details: {
|
||||
fa: {
|
||||
reason: String
|
||||
},
|
||||
en: {
|
||||
reason: String
|
||||
}
|
||||
},
|
||||
created_at: String
|
||||
})
|
||||
|
||||
module.exports = mongoose.model('ContactUsReason', ReasonSchema)
|
||||
@@ -1,19 +0,0 @@
|
||||
const mongoose = require('mongoose')
|
||||
|
||||
function image(file) {
|
||||
return `/uploads/images/gallery/${file}`
|
||||
}
|
||||
|
||||
const gallerySchema = mongoose.Schema({
|
||||
image: {type: String, get: image},
|
||||
created_at: String
|
||||
}, {
|
||||
toObject: {getters: true},
|
||||
toJSON: {getters: true}
|
||||
})
|
||||
|
||||
gallerySchema.virtual('thumb').get(function () {
|
||||
return '/uploads/images/gallery/thumb/thumb_' + this.image.split('gallery/')[1]
|
||||
})
|
||||
|
||||
module.exports = mongoose.model('Gallery', gallerySchema)
|
||||
@@ -0,0 +1,15 @@
|
||||
const mongoose = require('mongoose')
|
||||
|
||||
function catalog(pdf) {
|
||||
return '/uploads/pdf/' + pdf
|
||||
}
|
||||
|
||||
const MainCatalogSchema = mongoose.Schema({
|
||||
file: {type: String, get: catalog},
|
||||
created_at: String
|
||||
}, {
|
||||
toObject: {getters: true},
|
||||
toJSON: {getters: true}
|
||||
})
|
||||
|
||||
module.exports = mongoose.model('MainCatalog', MainCatalogSchema)
|
||||
@@ -0,0 +1,33 @@
|
||||
const mongoose = require('mongoose')
|
||||
|
||||
function image(file) {
|
||||
return `/uploads/images/projects/${file}`
|
||||
}
|
||||
|
||||
const ImagesSchema = mongoose.Schema({
|
||||
image: {type: String, get: image},
|
||||
created_at: String
|
||||
}, {
|
||||
toObject: {getters: true},
|
||||
toJSON: {getters: true}
|
||||
})
|
||||
|
||||
|
||||
const ProjectSchema = mongoose.Schema({
|
||||
images: [ImagesSchema],
|
||||
project_details: {
|
||||
fa: {
|
||||
name: String,
|
||||
description: String
|
||||
},
|
||||
en: {
|
||||
name: String,
|
||||
description: String
|
||||
}
|
||||
},
|
||||
date: String,
|
||||
created_at: String,
|
||||
updated_at: String
|
||||
})
|
||||
|
||||
module.exports = mongoose.model('Project', ProjectSchema)
|
||||
@@ -8,18 +8,11 @@ const SliderSchema = mongoose.Schema({
|
||||
image: {type: String, get: image},
|
||||
slider_details: {
|
||||
fa: {
|
||||
title: String,
|
||||
caption: String
|
||||
},
|
||||
en: {
|
||||
caption: String
|
||||
},
|
||||
de: {
|
||||
caption: String
|
||||
},
|
||||
tr: {
|
||||
caption: String
|
||||
},
|
||||
it: {
|
||||
title: String,
|
||||
caption: String
|
||||
}
|
||||
},
|
||||
|
||||
@@ -4,10 +4,9 @@ const AdminSchema = mongoose.Schema({
|
||||
name: String,
|
||||
username: String,
|
||||
password: String,
|
||||
roles: Array,
|
||||
created_at: String,
|
||||
updated_at: String,
|
||||
scope: String,
|
||||
scope: {type: String, default: 'admin'},
|
||||
token: String
|
||||
})
|
||||
|
||||
|
||||
@@ -7,15 +7,6 @@ const BlogCategorySchema = mongoose.Schema({
|
||||
},
|
||||
en: {
|
||||
name: String
|
||||
},
|
||||
de: {
|
||||
name: String
|
||||
},
|
||||
tr: {
|
||||
name: String
|
||||
},
|
||||
it: {
|
||||
name: String
|
||||
}
|
||||
},
|
||||
created_at: String,
|
||||
|
||||
@@ -18,21 +18,6 @@ const BlogPostSchema = mongoose.Schema({
|
||||
title: String,
|
||||
description: String,
|
||||
short_description: String
|
||||
},
|
||||
de: {
|
||||
title: String,
|
||||
description: String,
|
||||
short_description: String
|
||||
},
|
||||
tr: {
|
||||
title: String,
|
||||
description: String,
|
||||
short_description: String
|
||||
},
|
||||
it: {
|
||||
title: String,
|
||||
description: String,
|
||||
short_description: String
|
||||
}
|
||||
},
|
||||
created_at: String,
|
||||
|
||||
@@ -4,37 +4,28 @@ function productImage(img) {
|
||||
return '/uploads/images/products/' + img
|
||||
}
|
||||
|
||||
function ProductImageGallery(img) {
|
||||
return '/uploads/images/products/gallery/' + img
|
||||
function productPDF(file) {
|
||||
return '/uploads/pdf/' + file
|
||||
}
|
||||
|
||||
|
||||
const ProductFeatureSchema = mongoose.Schema({
|
||||
fa: {
|
||||
name: String,
|
||||
value: String
|
||||
},
|
||||
en: {
|
||||
name: String,
|
||||
value: String
|
||||
},
|
||||
de: {
|
||||
name: String,
|
||||
value: String
|
||||
},
|
||||
tr: {
|
||||
name: String,
|
||||
value: String
|
||||
},
|
||||
it: {
|
||||
name: String,
|
||||
value: String
|
||||
},
|
||||
const ProductImageSchema = mongoose.Schema({
|
||||
image: {type: String, get: productImage},
|
||||
created_at: String
|
||||
}, {
|
||||
toObject: {getters: true},
|
||||
toJSON: {getters: true}
|
||||
})
|
||||
|
||||
const ProductImageSchema = mongoose.Schema({
|
||||
image: {type: String, get: ProductImageGallery},
|
||||
const ProductPDFSchema = mongoose.Schema({
|
||||
file: {type: String, get: productPDF},
|
||||
pdf_details: {
|
||||
fa: {
|
||||
name: String
|
||||
},
|
||||
en: {
|
||||
name: String
|
||||
}
|
||||
},
|
||||
created_at: String
|
||||
}, {
|
||||
toObject: {getters: true},
|
||||
@@ -42,53 +33,47 @@ const ProductImageSchema = mongoose.Schema({
|
||||
})
|
||||
|
||||
const ProductSchema = mongoose.Schema({
|
||||
image: {type: String, get: productImage},
|
||||
stock: Number,
|
||||
cover: {type: String, get: productImage},
|
||||
images: [ProductImageSchema],
|
||||
more_section_image1: {type: String, get: productImage},
|
||||
more_section_image2: {type: String, get: productImage},
|
||||
render_image1: {type: String, get: productImage},
|
||||
render_image2: {type: String, get: productImage},
|
||||
chart_image: {type: String, get: productImage},
|
||||
pdf_files: [ProductPDFSchema],
|
||||
category: String,
|
||||
more_section: {type: Boolean, default: true},
|
||||
download_section: {type: Boolean, default: true},
|
||||
product_details: {
|
||||
fa: {
|
||||
name: String,
|
||||
description: String,
|
||||
price: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
short_description: String,
|
||||
page_title: String,
|
||||
page_description: String,
|
||||
more_title1: String,
|
||||
more_description1: String,
|
||||
more_title2: String,
|
||||
more_description2: String,
|
||||
render_caption1: String,
|
||||
render_caption2: String,
|
||||
chart_title: String,
|
||||
chart_description: String
|
||||
},
|
||||
en: {
|
||||
name: String,
|
||||
description: String,
|
||||
price: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
de: {
|
||||
name: String,
|
||||
description: String,
|
||||
price: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
it: {
|
||||
name: String,
|
||||
description: String,
|
||||
price: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
tr: {
|
||||
name: String,
|
||||
description: String,
|
||||
price: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
short_description: String,
|
||||
page_title: String,
|
||||
page_description: String,
|
||||
more_title1: String,
|
||||
more_description1: String,
|
||||
more_title2: String,
|
||||
more_description2: String,
|
||||
render_caption1: String,
|
||||
render_caption2: String,
|
||||
chart_title: String,
|
||||
chart_description: String
|
||||
}
|
||||
},
|
||||
product_features: [ProductFeatureSchema],
|
||||
product_images: [ProductImageSchema],
|
||||
created_at: String,
|
||||
updated_at: String
|
||||
}, {
|
||||
|
||||
@@ -1,39 +1,16 @@
|
||||
const mongoose = require('mongoose')
|
||||
|
||||
function image(img) {
|
||||
return '/uploads/images/products/category/' + img
|
||||
}
|
||||
|
||||
const ProductCategorySchema = mongoose.Schema({
|
||||
image: {type: String, get: image},
|
||||
cover: {type: String, get: image},
|
||||
category_details: {
|
||||
fa: {
|
||||
name: String,
|
||||
caption: String
|
||||
name: String
|
||||
},
|
||||
en: {
|
||||
name: String,
|
||||
caption: String
|
||||
},
|
||||
de: {
|
||||
name: String,
|
||||
caption: String
|
||||
},
|
||||
tr: {
|
||||
name: String,
|
||||
caption: String
|
||||
},
|
||||
it: {
|
||||
name: String,
|
||||
caption: String
|
||||
name: String
|
||||
}
|
||||
},
|
||||
created_at: String,
|
||||
updated_at: String
|
||||
}, {
|
||||
toObject: {getters: true},
|
||||
toJSON: {getters: true}
|
||||
})
|
||||
|
||||
module.exports = mongoose.model('ProductCategory', ProductCategorySchema)
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
const mongoose = require('mongoose')
|
||||
|
||||
const Cart_ItemSchema = mongoose.Schema({
|
||||
user_id: String,
|
||||
product_id: String,
|
||||
quantity: String,
|
||||
created_at: String,
|
||||
updated_at: String
|
||||
})
|
||||
|
||||
module.exports = mongoose.model('Cart_Item', Cart_ItemSchema)
|
||||
@@ -1,30 +0,0 @@
|
||||
const mongoose = require('mongoose')
|
||||
|
||||
const StatusSchema = mongoose.Schema({
|
||||
status: {
|
||||
type: String,
|
||||
enum: ['incomplete','processing', 'packing', 'sent','delivered'],
|
||||
default: 'processing'
|
||||
},
|
||||
created_at: String
|
||||
})
|
||||
|
||||
const Order_itemsSchema = mongoose.Schema({
|
||||
product_id: String,
|
||||
quantity: Number,
|
||||
price: Number,
|
||||
price_unit: String,
|
||||
created_at: String
|
||||
})
|
||||
|
||||
const OrderSchema = mongoose.Schema({
|
||||
user_id: String,
|
||||
number: Number,
|
||||
address: Object,
|
||||
statuses: [StatusSchema],
|
||||
order_items: [Order_itemsSchema],
|
||||
created_at: String,
|
||||
updated_at: String
|
||||
})
|
||||
|
||||
module.exports = mongoose.model('Order', OrderSchema)
|
||||
@@ -1,43 +0,0 @@
|
||||
const mongoose = require('mongoose')
|
||||
|
||||
const AddressSchema = mongoose.Schema({
|
||||
country: String,
|
||||
province: String,
|
||||
city: String,
|
||||
address: String,
|
||||
postal_code: String,
|
||||
plaque: String,
|
||||
block_number: String,
|
||||
receiver_first_name: String,
|
||||
receiver_last_name: String,
|
||||
receiver_mobile: String,
|
||||
created_at: String
|
||||
})
|
||||
|
||||
|
||||
const UserSchema = mongoose.Schema({
|
||||
first_name: String,
|
||||
last_name: String,
|
||||
type: {type: String, enum: ['personal', 'company'], default: 'personal'},
|
||||
company_name: String,
|
||||
email_personal: String,
|
||||
email_company: String,
|
||||
fb_id_personal: String,
|
||||
fb_id_company: String,
|
||||
ig_id_personal: String,
|
||||
ig_id_company: String,
|
||||
skype_id_personal: String,
|
||||
skype_id_company: String,
|
||||
addresses: [AddressSchema],
|
||||
phone_number: String,
|
||||
password: String,
|
||||
confirmed: {type: Boolean, default: false},
|
||||
confirmation_key: String,
|
||||
scope: String,
|
||||
token: String,
|
||||
reset_pass_key: String,
|
||||
created_at: String,
|
||||
updated_at: String
|
||||
})
|
||||
|
||||
module.exports = mongoose.model('User', UserSchema)
|
||||
+1
-10
@@ -1,21 +1,12 @@
|
||||
const {Router} = require('express')
|
||||
const router = Router()
|
||||
const adminController = require('../controllers/adminController')
|
||||
const userController = require('../controllers/userController')
|
||||
|
||||
////////////////////// admin routes
|
||||
router.post('/admin/register', adminController.register)
|
||||
// router.post('/admin/register', adminController.register)
|
||||
|
||||
router.post('/admin/login', adminController.login)
|
||||
router.post('/admin/logout', adminController.logout)
|
||||
router.get('/admin/user', adminController.getUser)
|
||||
|
||||
|
||||
////////////////////// user routes
|
||||
router.post('/user/register', userController.register)
|
||||
|
||||
router.post('/user/login', userController.login)
|
||||
router.post('/user/logout', userController.logout)
|
||||
router.get('/user/user', userController.getUser)
|
||||
|
||||
module.exports = router
|
||||
|
||||
+18
-28
@@ -2,16 +2,14 @@ const {Router} = require('express')
|
||||
const router = Router()
|
||||
/////////////////////////////////////////////////////////// controllers
|
||||
const sliderController = require('../controllers/sliderController')
|
||||
const aboutPageContent_controller = require('../controllers/aboutPageContent_controller')
|
||||
const productController = require('../controllers/productController')
|
||||
const productCategoryController = require('../controllers/productCategoryController')
|
||||
const blogCategoryController = require('../controllers/blogCategoryController')
|
||||
const blogPostController = require('../controllers/blogPostController')
|
||||
const userController = require('../controllers/userController')
|
||||
const orderController = require('../controllers/orderController')
|
||||
const galleryController = require('../controllers/galleryController')
|
||||
const projectController = require('../controllers/projectController')
|
||||
const contactPageController = require('../controllers/contactPageController')
|
||||
const broadcastController = require('../controllers/broadcastController')
|
||||
const contactUsReasonController = require('../controllers/contactUsReasonController')
|
||||
const mainCatalogController = require('../controllers/mainCatalogController')
|
||||
|
||||
/////////////////////////////////////////////////////////// routes
|
||||
//////////////// slider
|
||||
@@ -19,9 +17,6 @@ router.post('/slider', sliderController.create)
|
||||
router.put('/slider/:id', sliderController.update)
|
||||
router.delete('/slider/:id', sliderController.delete)
|
||||
|
||||
//////////////// about page content
|
||||
router.post('/aboutPage', aboutPageContent_controller.create)
|
||||
|
||||
//////////////// blog categories
|
||||
router.post('/blogCategories', blogCategoryController.create)
|
||||
router.put('/blogCategories/:id', blogCategoryController.update)
|
||||
@@ -46,31 +41,26 @@ router.delete('/products/:id', productController.deleteProduct)
|
||||
router.post('/productImage', productController.createProductImage)
|
||||
router.delete('/productImage/:imageID', productController.deleteProductImage)
|
||||
|
||||
// product feature
|
||||
router.post('/productFeature', productController.createProductFeature)
|
||||
router.delete('/productFeature/:featureID', productController.deleteProductFeature)
|
||||
// product PDF
|
||||
router.post('/productPDF', productController.createPDF)
|
||||
router.delete('/productPDF/:pdfID', productController.deletePDF)
|
||||
|
||||
//////////////// users
|
||||
router.get('/customers', userController.getAllUsers)
|
||||
router.get('/customers/:user_id', userController.getOneUser)
|
||||
|
||||
// user orders
|
||||
router.get('/orders', orderController.getAllOrders)
|
||||
router.get('/orders/:user_id', orderController.getOrders)
|
||||
router.get('/order/:order_id', orderController.getOneOrder)
|
||||
router.post('/addStatusToOrder/:order_id', orderController.addStatusToOrder)
|
||||
|
||||
//////////////// gallery
|
||||
router.post('/gallery', galleryController.create)
|
||||
router.delete('/gallery/:id', galleryController.delete)
|
||||
//////////////// projects
|
||||
router.post('/projects', projectController.create)
|
||||
router.put('/projects/:id', projectController.update)
|
||||
router.delete('/projects/:id', projectController.delete)
|
||||
// add images
|
||||
router.post('/projects/images/:id', projectController.addImage)
|
||||
router.delete('/projects/images/:id', projectController.deleteImage)
|
||||
|
||||
//////////////// contact us
|
||||
router.get('/contact', contactPageController.getAll)
|
||||
router.get('/contact/:id', contactPageController.getOne)
|
||||
/// contact us reason
|
||||
router.post('/contact/reason', contactUsReasonController.create)
|
||||
router.delete('/contact/reason/:id', contactUsReasonController.delete)
|
||||
|
||||
//////////////// broadcast
|
||||
router.post('/broadcast', broadcastController.create)
|
||||
router.get('/broadcast', broadcastController.getAll)
|
||||
router.delete('/broadcast/:id', broadcastController.delete)
|
||||
///////////////// main catalog
|
||||
router.post('/catalog', mainCatalogController.create)
|
||||
|
||||
module.exports = router
|
||||
|
||||
+11
-24
@@ -3,35 +3,20 @@ const router = Router()
|
||||
|
||||
/////////////////////////////////////////////////////////// controllers
|
||||
const sliderController = require('../controllers/sliderController')
|
||||
const localeController = require('../controllers/localeController')
|
||||
const aboutPageContent_controller = require('../controllers/aboutPageContent_controller')
|
||||
const productController = require('../controllers/productController')
|
||||
const productCategoryController = require('../controllers/productCategoryController')
|
||||
const blogCategoryController = require('../controllers/blogCategoryController')
|
||||
const blogPostController = require('../controllers/blogPostController')
|
||||
const galleryController = require('../controllers/galleryController')
|
||||
const projectController = require('../controllers/projectController')
|
||||
const contactPageController = require('../controllers/contactPageController')
|
||||
const userController = require('../controllers/userController')
|
||||
|
||||
const contactUsReasonController = require('../controllers/contactUsReasonController')
|
||||
const mainCatalogController = require('../controllers/mainCatalogController')
|
||||
/////////////////////////////////////////////////////////// routes
|
||||
|
||||
//////////////// locale
|
||||
router.get('/locale', localeController.get)
|
||||
|
||||
//////////////// active user account
|
||||
router.post('/activeUser/:key', userController.activation)
|
||||
|
||||
//////////////// reset pass
|
||||
router.post('/resetPass', userController.resetPassKey)
|
||||
router.post('/setNewPass/:key', userController.setNewPass)
|
||||
|
||||
//////////////// slider
|
||||
router.get('/slider', sliderController.getAll)
|
||||
router.get('/slider/:id', sliderController.getOne)
|
||||
|
||||
//////////////// about page content
|
||||
router.get('/aboutPage', aboutPageContent_controller.get)
|
||||
|
||||
//////////////// blog category
|
||||
router.get('/blogCategories', blogCategoryController.getAll)
|
||||
router.get('/blogCategories/:id', blogCategoryController.getOne)
|
||||
@@ -49,14 +34,16 @@ router.get('/products/:category', productController.getAllProductsByCategory)
|
||||
router.get('/products/', productController.getAllProducts)
|
||||
router.get('/product/:id', productController.getOneProduct)
|
||||
|
||||
//////////////// gallery
|
||||
router.get('/gallery', galleryController.getAll)
|
||||
router.get('/gallery/:id', galleryController.getOne)
|
||||
|
||||
// //////////////// subscribers
|
||||
// router.post('/subscribers',subscribersController.create)
|
||||
//////////////// projects
|
||||
router.get('/projects', projectController.getAll)
|
||||
router.get('/projects/:id', projectController.getOne)
|
||||
|
||||
//////////////// contact us
|
||||
router.post('/contact', contactPageController.create)
|
||||
/// contact us reason
|
||||
router.get('/contact/reason', contactUsReasonController.getAll)
|
||||
|
||||
//////////////// main catalog
|
||||
router.get('/catalog', mainCatalogController.get)
|
||||
|
||||
module.exports = router
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
const {Router} = require('express')
|
||||
const router = Router()
|
||||
|
||||
const orderController = require('../controllers/orderController')
|
||||
const userController = require('../controllers/userController')
|
||||
const broadcastController = require('../controllers/broadcastController')
|
||||
|
||||
// cart
|
||||
router.post('/addToCart', orderController.addToCart)
|
||||
router.put('/updateCart/:item_id', orderController.updateCart)
|
||||
router.get('/cartItems/:user_id', orderController.getCartItems)
|
||||
router.delete('/deleteItem/:item_id', orderController.deleteFromCart)
|
||||
|
||||
// order
|
||||
router.post('/addOrder', orderController.addOrder)
|
||||
router.post('/addAddressToOrder/:order_id', orderController.addAddressToOrder)
|
||||
router.get('/orders/:user_id', orderController.getOrders)
|
||||
router.get('/order/:order_id', orderController.getOneOrder)
|
||||
|
||||
// address
|
||||
router.post('/addAddress', userController.addAdress)
|
||||
router.delete('/addresses/:address_id', userController.deleteAddress)
|
||||
router.get('/addresses/:user_id', userController.getAddresses)
|
||||
|
||||
// update profile
|
||||
router.put('/profile', userController.updateUser)
|
||||
router.post('/password', userController.updateUserPassword)
|
||||
|
||||
// broadcast
|
||||
router.get('/broadcast', broadcastController.getAll)
|
||||
router.post('/broadcast/:id', broadcastController.getOne)
|
||||
|
||||
module.exports = router
|
||||
+111
-16
@@ -4,6 +4,7 @@ module.exports = {
|
||||
// developer validations
|
||||
remember_me: 'پارامتر remember_me الزامی است',
|
||||
// registration validations
|
||||
name: 'نام را وارد کنید',
|
||||
first_name: 'نام را وارد کنید',
|
||||
last_name: 'نام خانوادگی را وارد کنید',
|
||||
email: 'ایمیل را وارد کنید',
|
||||
@@ -13,7 +14,6 @@ module.exports = {
|
||||
username: 'نام کاربری را وارد کنید',
|
||||
phone_number: 'شماره تماس را وارد کنید',
|
||||
password: 'پسورد را وارد کنید',
|
||||
password_confirmation: 'پسورد ها یکی نیست',
|
||||
// addressing validations
|
||||
country: 'کشور را وارد کنید',
|
||||
province: 'استان را وارد کنید',
|
||||
@@ -31,8 +31,11 @@ module.exports = {
|
||||
category: 'دسته بندی را انتخاب کنید',
|
||||
image: 'عکس اجباری است',
|
||||
cover: 'کاور اجباری است',
|
||||
file: 'فایل اجباری است',
|
||||
message: 'پیام را بنویسید',
|
||||
quantity: 'تعداد را وارد کنید'
|
||||
quantity: 'تعداد را وارد کنید',
|
||||
date: 'تاریخ را وارد کنید',
|
||||
reason: 'دلیل را انتخاب کنید'
|
||||
},
|
||||
format: {
|
||||
phone_number: 'فرمت شماره تماس صحیح نیست',
|
||||
@@ -102,7 +105,23 @@ module.exports = {
|
||||
expired_reset_link: 'این لینک بازیابی منقضی شده است',
|
||||
email_not_confirmed: 'ابتدا ایمیل خود را تایید کنید،لینک فعال سازی قبلا برای شما فرستاده شده است.',
|
||||
expired_activation_link: 'این لینک فعال سازی منقضی شده است',
|
||||
success_activation: 'اکانت شما با موفقیت فعال شد'
|
||||
success_activation: 'اکانت شما با موفقیت فعال شد',
|
||||
passwords_not_match: 'پسورد ها یکی نیست',
|
||||
},
|
||||
file_types: {
|
||||
jpg: 'فقط فرمت jpg قابل قبول است',
|
||||
png: 'فقط فرمت png قابل قبول است',
|
||||
gif: 'فقط فرمت gif قابل قبول است',
|
||||
pdf: 'فقط فرمت pdf قابل قبول است',
|
||||
txt: 'فقط فرمت txt قابل قبول است',
|
||||
log: 'فقط فرمت log قابل قبول است',
|
||||
mp3: 'فقط فرمت mp3 قابل قبول است',
|
||||
ogg: 'فقط فرمت ogg قابل قبول است',
|
||||
wmv: 'فقط فرمت wmv قابل قبول است',
|
||||
mp4: 'فقط فرمت mp4 قابل قبول است',
|
||||
mov: 'فقط فرمت mov قابل قبول است',
|
||||
mkv: 'فقط فرمت mkv قابل قبول است',
|
||||
flv: 'فقط فرمت flv قابل قبول است'
|
||||
}
|
||||
},
|
||||
en: {
|
||||
@@ -110,7 +129,8 @@ module.exports = {
|
||||
// developer validations
|
||||
remember_me: 'Remember_me parameter required',
|
||||
// registration validations
|
||||
first_name: 'Enter name',
|
||||
name: 'Enter name',
|
||||
first_name: 'Enter first name',
|
||||
last_name: 'Enter last name',
|
||||
email: 'Enter email',
|
||||
email_personal: 'Personal email is required',
|
||||
@@ -119,7 +139,6 @@ module.exports = {
|
||||
username: 'Enter username',
|
||||
phone_number: 'Enter phone number',
|
||||
password: 'Enter password',
|
||||
password_confirmation: 'Passwords are not the same',
|
||||
// addressing validations
|
||||
country: 'Enter country',
|
||||
province: 'Enter province',
|
||||
@@ -137,8 +156,11 @@ module.exports = {
|
||||
category: 'Select category',
|
||||
image: 'Image is required',
|
||||
cover: 'Cover is required',
|
||||
file: 'File is required',
|
||||
message: 'Write message',
|
||||
quantity: 'Enter quantity'
|
||||
quantity: 'Enter quantity',
|
||||
date: 'Enter date',
|
||||
reason: 'Select reason'
|
||||
},
|
||||
format: {
|
||||
phone_number: 'Phone number format in incorrect',
|
||||
@@ -208,7 +230,23 @@ module.exports = {
|
||||
expired_reset_link: 'The current reset pass link has been expired',
|
||||
email_not_confirmed: 'Confirm your email first, the activation link has already been sent to you.',
|
||||
expired_activation_link: 'This activation link has expired',
|
||||
success_activation: 'Your account has been successfully activated'
|
||||
success_activation: 'Your account has been successfully activated',
|
||||
passwords_not_match: 'Passwords are not the same',
|
||||
},
|
||||
file_types: {
|
||||
jpg: 'Only jpg format is acceptable',
|
||||
png: 'Only png format is acceptable',
|
||||
gif: 'Only gif format is acceptable',
|
||||
pdf: 'Only pdf format is acceptable',
|
||||
txt: 'Only txt format is acceptable',
|
||||
log: 'Only log format is acceptable',
|
||||
mp3: 'Only mp3 format is acceptable',
|
||||
ogg: 'Only ogg format is acceptable',
|
||||
wmv: 'Only wmv format is acceptable',
|
||||
mp4: 'Only mp4 format is acceptable',
|
||||
mov: 'Only mov format is acceptable',
|
||||
mkv: 'Only mkv format is acceptable',
|
||||
flv: 'Only flv format is acceptable'
|
||||
}
|
||||
},
|
||||
de: {
|
||||
@@ -216,6 +254,7 @@ module.exports = {
|
||||
// developer validations
|
||||
remember_me: 'Remember_me-Parameter erforderlich',
|
||||
// registration validations
|
||||
name: 'Name eingeben',
|
||||
first_name: 'Name eingeben',
|
||||
last_name: 'Nachnamen eingeben',
|
||||
email: 'Email eingeben',
|
||||
@@ -225,7 +264,6 @@ module.exports = {
|
||||
username: 'Geben Sie den Benutzernamen ein',
|
||||
phone_number: 'Telefonnummer eingeben',
|
||||
password: 'Passwort eingeben',
|
||||
password_confirmation: 'Passwörter sind nicht dasselbe',
|
||||
// addressing validations
|
||||
country: 'Land eingeben',
|
||||
province: 'Stadt betreten',
|
||||
@@ -243,8 +281,11 @@ module.exports = {
|
||||
category: 'Kategorie wählen',
|
||||
image: 'Bild ist erforderlich',
|
||||
cover: 'Bild ist erforderlich Abdeckung ist erforderlich',
|
||||
file: 'Datei ist erforderlich',
|
||||
message: 'Nachricht schreiben',
|
||||
quantity: 'Menge eingeben'
|
||||
quantity: 'Menge eingeben',
|
||||
date: 'Enter date',
|
||||
reason: 'Grund auswählen'
|
||||
},
|
||||
format: {
|
||||
phone_number: 'Telefonnummernformat falsch',
|
||||
@@ -314,7 +355,23 @@ module.exports = {
|
||||
expired_reset_link: 'Der aktuelle Reset-Pass-Link ist abgelaufen',
|
||||
email_not_confirmed: "Bestätigen Sie zuerst Ihre E-Mail, der Aktivierungslink wurde bereits an Sie gesendet.",
|
||||
expired_activation_link: 'Dieser Aktivierungslink ist abgelaufen',
|
||||
success_activation: 'Ihr Konto wurde erfolgreich aktiviert'
|
||||
success_activation: 'Ihr Konto wurde erfolgreich aktiviert',
|
||||
passwords_not_match: 'Passwörter sind nicht dasselbe'
|
||||
},
|
||||
file_types: {
|
||||
jpg: 'Nur das jpg-Format ist akzeptabel',
|
||||
png: 'Nur das png-Format ist akzeptabel',
|
||||
gif: 'Nur das gif-Format ist akzeptabel',
|
||||
pdf: 'Nur das PDF-Format ist akzeptabel',
|
||||
txt: 'Nur das txt-Format ist akzeptabel',
|
||||
log: 'Nur das log-Format ist akzeptabel',
|
||||
mp3: 'Nur das mp3-Format ist akzeptabel',
|
||||
ogg: 'Nur das ogg-Format ist akzeptabel',
|
||||
wmv: 'Nur das wmv-Format ist akzeptabel',
|
||||
mp4: 'Nur das mp4-Format ist akzeptabel',
|
||||
mov: 'Nur das mov-Format ist akzeptabel',
|
||||
mkv: 'Nur das mkv-Format ist akzeptabel',
|
||||
flv: 'Nur das flv-Format ist akzeptabel'
|
||||
}
|
||||
},
|
||||
tr: {
|
||||
@@ -322,6 +379,7 @@ module.exports = {
|
||||
// geliştirici doğrulamaları
|
||||
Remember_me: 'Remember_me parametresi gerekli',
|
||||
// kayıt doğrulamaları
|
||||
name: 'Adı girin',
|
||||
first_name: 'Adı girin',
|
||||
last_name: 'Soyadı girin',
|
||||
email: 'E-posta girin',
|
||||
@@ -331,7 +389,6 @@ module.exports = {
|
||||
username: 'Kullanıcı adını girin',
|
||||
phone_number: 'Telefon numarasını girin',
|
||||
password: 'Şifre girin',
|
||||
password_confirmation: 'Şifreler aynı değil',
|
||||
// doğrulamaları adresleme
|
||||
country: 'Ülke girin',
|
||||
province: 'İl girin',
|
||||
@@ -349,8 +406,11 @@ module.exports = {
|
||||
category: 'Kategori seçin',
|
||||
image: 'Resim gerekli',
|
||||
cover: 'Kapak gereklidir',
|
||||
file: 'Dosya gerekli',
|
||||
message: 'Mesaj yaz',
|
||||
quantity: 'Miktar girin'
|
||||
quantity: 'Miktar girin',
|
||||
date: 'Enter date',
|
||||
reason: 'Nedeni seçin'
|
||||
},
|
||||
format: {
|
||||
phone_number: 'Telefon numarası biçimi yanlış',
|
||||
@@ -420,7 +480,23 @@ module.exports = {
|
||||
expired_reset_link: 'Mevcut sıfırlama geçiş bağlantısının süresi doldu',
|
||||
email_not_confirmed: 'Önce e-postanızı onaylayın, aktivasyon bağlantısı size zaten gönderildi.',
|
||||
expired_activation_link: "Bu aktivasyon bağlantısının süresi doldu",
|
||||
success_activation: 'Hesabınız başarıyla etkinleştirildi'
|
||||
success_activation: 'Hesabınız başarıyla etkinleştirildi',
|
||||
passwords_not_match: 'Şifreler aynı değil'
|
||||
},
|
||||
file_types: {
|
||||
jpg: 'Yalnızca jpg formatı kabul edilebilir',
|
||||
png: 'Sadece png formatı kabul edilebilir',
|
||||
gif: 'Yalnızca gif formatı kabul edilebilir',
|
||||
pdf: 'Yalnızca pdf formatı kabul edilebilir',
|
||||
txt: 'Yalnızca txt formatı kabul edilebilir',
|
||||
log: 'Yalnızca log formatı kabul edilebilir',
|
||||
mp3: 'Yalnızca mp3 formatı kabul edilebilir',
|
||||
ogg: 'Yalnızca ogg formatı kabul edilebilir',
|
||||
wmv: 'Yalnızca wmv formatı kabul edilebilir',
|
||||
mp4: 'Yalnızca mp4 formatı kabul edilebilir',
|
||||
mov: 'Yalnızca mov formatı kabul edilebilir',
|
||||
mkv: 'Yalnızca mkv formatı kabul edilebilir',
|
||||
flv: 'Yalnızca flv biçimi kabul edilebilir'
|
||||
}
|
||||
},
|
||||
it: {
|
||||
@@ -428,6 +504,7 @@ module.exports = {
|
||||
// convalide dello sviluppatore
|
||||
Remember_me: "Remember_me parameter required",
|
||||
// convalide della registrazione
|
||||
name: "Inserisci nome",
|
||||
first_name: "Inserisci nome",
|
||||
last_name: "Inserisci il cognome",
|
||||
email: "Enter email",
|
||||
@@ -437,7 +514,6 @@ module.exports = {
|
||||
username: "Inserisci nome utente",
|
||||
phone_number: "Inserisci numero di telefono",
|
||||
password: "Inserisci password",
|
||||
password_confirmation: "Le password non sono le stesse",
|
||||
// indirizzamento delle convalide
|
||||
country: "Inserisci paese",
|
||||
province: "Inserisci provincia",
|
||||
@@ -455,8 +531,11 @@ module.exports = {
|
||||
category: "Seleziona categoria",
|
||||
image: "L'immagine è obbligatoria",
|
||||
cover: "Cover is required",
|
||||
file: "Il file è obbligatorio",
|
||||
message: "Scrivi messaggio",
|
||||
quantity: "Inserisci quantità"
|
||||
quantity: "Inserisci quantità",
|
||||
date: 'Enter date',
|
||||
reason: 'Seleziona motivo'
|
||||
},
|
||||
format: {
|
||||
phone_number: "Formato del numero di telefono non corretto",
|
||||
@@ -526,7 +605,23 @@ module.exports = {
|
||||
expired_reset_link: "L'attuale link del passaggio di reimpostazione è scaduto",
|
||||
email_not_confirmed: "Conferma prima la tua email, il link di attivazione ti è già stato inviato.",
|
||||
expired_activation_link: "Questo link di attivazione è scaduto",
|
||||
success_activation: "Il tuo account è stato attivato con successo"
|
||||
success_activation: "Il tuo account è stato attivato con successo",
|
||||
passwords_not_match: "Le password non sono le stesse"
|
||||
},
|
||||
file_types: {
|
||||
jpg: "È accettabile solo il formato jpg",
|
||||
png: "È accettabile solo il formato png",
|
||||
gif: "È accettabile solo il formato GIF",
|
||||
pdf: "È accettabile solo il formato pdf",
|
||||
txt: "È accettabile solo il formato txt",
|
||||
log: "È accettabile solo il formato log",
|
||||
mp3: "È accettabile solo il formato mp3",
|
||||
ogg: "È accettabile solo il formato ogg",
|
||||
wmv: "È accettabile solo il formato wmv",
|
||||
mp4: "È accettabile solo il formato mp4",
|
||||
mov: "È accettabile solo il formato mov",
|
||||
mkv: "È accettabile solo il formato mkv",
|
||||
flv: "È accettabile solo il formato flv"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
}
|
||||
|
||||
////////////////////////////////////// variables
|
||||
$header: rgba(#784FAE, 1);
|
||||
$header: rgba(#1B407C, 1);
|
||||
$sidebar: rgba(#424242e3, 1);
|
||||
$headerLogoTextColor: #fff;
|
||||
$headerFontColor: #fff;
|
||||
@@ -110,19 +110,25 @@ $panelBg: #fff;
|
||||
}
|
||||
|
||||
.admin--content {
|
||||
padding-top: 60px;
|
||||
height: calc(100vh - 55px);
|
||||
flex-basis: calc(100% - 300px);
|
||||
background: $bg;
|
||||
direction: rtl !important;
|
||||
text-align: right;
|
||||
overflow-y: auto;
|
||||
position: relative;
|
||||
|
||||
.title {
|
||||
//width: 100%;
|
||||
.admin-title-bar {
|
||||
width: calc(100vw - 285px);
|
||||
height: 55px;
|
||||
background: $titleBg;
|
||||
color: $titleColor;
|
||||
padding: 0 15px;
|
||||
position: fixed;
|
||||
top: 56px;
|
||||
left: 15px;
|
||||
z-index: 5;
|
||||
|
||||
h2 {
|
||||
margin-left: auto;
|
||||
@@ -131,6 +137,11 @@ $panelBg: #fff;
|
||||
|
||||
button {
|
||||
margin-right: 10px;
|
||||
color: $titleColor;
|
||||
|
||||
span {
|
||||
color: $titleColor;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
@@ -138,7 +149,7 @@ $panelBg: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.panel {
|
||||
.admin-panel {
|
||||
background: $panelBg;
|
||||
@include borderRadius(5px);
|
||||
@include boxShadow(0 2px 4px rgba(#000, 0.4));
|
||||
@@ -190,6 +201,10 @@ $panelBg: #fff;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
span {
|
||||
color: $asideIcon;
|
||||
}
|
||||
|
||||
.badge {
|
||||
display: inline-block;
|
||||
width: 23px;
|
||||
@@ -213,7 +228,7 @@ $panelBg: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.user {
|
||||
.admin-user {
|
||||
padding: 20px 15px;
|
||||
color: $usernameColor;
|
||||
|
||||
@@ -223,7 +238,7 @@ $panelBg: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.language {
|
||||
.admin-language {
|
||||
width: 100%;
|
||||
|
||||
select {
|
||||
|
||||
@@ -752,3 +752,41 @@ section {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.filters {
|
||||
margin: 0 auto 50px;
|
||||
|
||||
ul {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
|
||||
li {
|
||||
margin: 10px 20px;
|
||||
color: rgba(#000, 0.5);
|
||||
cursor: pointer;
|
||||
@extend %userSelect;
|
||||
|
||||
p {
|
||||
text-align: center;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
display: block;
|
||||
height: 2px;
|
||||
width: 0;
|
||||
background: $red;
|
||||
margin: 0 auto;
|
||||
@include transition(0.1s);
|
||||
}
|
||||
|
||||
&.active {
|
||||
&::after {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+26
-28
@@ -32,7 +32,7 @@
|
||||
|
||||
.hero {
|
||||
.bg {
|
||||
background-image: url("../img/home/hp-s1-i1.jpg");
|
||||
//background-image: url("../img/home/hp-s1-i1.jpg");
|
||||
}
|
||||
|
||||
.txt--home {
|
||||
@@ -551,21 +551,6 @@
|
||||
.s2 {
|
||||
text-align: center;
|
||||
|
||||
.filters {
|
||||
margin: 0 auto;
|
||||
max-width: 700px;
|
||||
background: red;
|
||||
|
||||
ul {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
li {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.product {
|
||||
display: block;
|
||||
background: #fff;
|
||||
@@ -587,6 +572,15 @@
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.no-product {
|
||||
width: 100%;
|
||||
background: $red;
|
||||
color: #fff;
|
||||
padding: 20px;
|
||||
margin-bottom: 50px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.s3 {
|
||||
@@ -710,6 +704,7 @@
|
||||
img {
|
||||
width: 60%;
|
||||
margin: 0 auto;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -820,6 +815,10 @@
|
||||
h4 {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.description {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -907,22 +906,12 @@
|
||||
text-align: center;
|
||||
padding-bottom: 0;
|
||||
|
||||
ul {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
|
||||
li {
|
||||
margin: 10px 20px;
|
||||
color: rgba(#000, 0.5);
|
||||
cursor: pointer;
|
||||
@extend %userSelect;
|
||||
}
|
||||
.filters {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.s3 {
|
||||
|
||||
.post {
|
||||
margin-top: 50px;
|
||||
|
||||
@@ -988,6 +977,15 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.no-post {
|
||||
width: 100%;
|
||||
background: $red;
|
||||
color: #fff;
|
||||
padding: 20px;
|
||||
margin-top: 70px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<header class="header">
|
||||
<div class="lang-bar">
|
||||
<a :href="catalog_link" download="catalog.pdf" target="_blank" class="catalog-download">
|
||||
<a :href="catalog.file" target="_blank" class="catalog-download">
|
||||
<span>{{staticData.catalog}}</span>
|
||||
<span> </span>
|
||||
<i class="fas fa-download"></i>
|
||||
@@ -89,9 +89,13 @@
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
catalog_link: this.$store.state.staticData.catalog_link
|
||||
catalog: null
|
||||
}
|
||||
},
|
||||
async fetch() {
|
||||
let catalog = await this.$axios.get('/api/public/catalog')
|
||||
this.catalog = catalog.data
|
||||
},
|
||||
computed: {
|
||||
staticData() {
|
||||
return this.$store.state.staticData.header[this.$route.params.lang]
|
||||
@@ -119,7 +123,6 @@
|
||||
$('.header').removeClass('header-small')
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
|
||||
<admin-aside-item icon="fas fa-presentation" :link="{name: 'admin-slider'}" text="اسلایدر"/>
|
||||
|
||||
<admin-aside-item icon="fas fa-image" :link="{name: 'admin-gallery'}" text="گالری"/>
|
||||
|
||||
<admin-aside-item icon="fa fa-gift" text="محصولات" :hasChild="true">
|
||||
<admin-aside-item :link="{name: 'admin-products'}" text="لیست محصولات"/>
|
||||
<admin-aside-item :link="{name: 'admin-products-category'}" text="دسته بندی محصولات"/>
|
||||
@@ -16,17 +14,12 @@
|
||||
<admin-aside-item :link="{name: 'admin-blog-category'}" text="دسته بندی بلاگ"/>
|
||||
</admin-aside-item>
|
||||
|
||||
|
||||
<admin-aside-item icon="fas fa-user-friends" :link="{name: 'admin-customers'}" text="لیست مشتریان"/>
|
||||
|
||||
<admin-aside-item icon="fas fa-bags-shopping" :link="{name: 'admin-orders'}" text="لیست سفارشات"/>
|
||||
<admin-aside-item icon="fas fa-bags-shopping" :link="{name: 'admin-projects'}" text="پروژه ها"/>
|
||||
|
||||
<admin-aside-item icon="fas fa-envelope" :badge="$store.state.admin.unread" :link="{name: 'admin-messages'}" text="پیام های ارتباط با ما"/>
|
||||
|
||||
<admin-aside-item icon="fa fa-bullhorn" :link="{name: 'admin-broadcast'}" text="ارسال پیام برای مشتریان"/>
|
||||
|
||||
<admin-aside-item icon="far fa-file" :link="{name: 'admin-about'}" text="محتوای صفحه درباره ما"/>
|
||||
|
||||
<admin-aside-item icon="fas fa-file-pdf" :link="{name: 'admin-catalog'}" text="آپلود فایل کاتالوگ"/>
|
||||
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
<a href="/" target="_blank" class="customer">
|
||||
<!-- customer logo -->
|
||||
<div class="logo">
|
||||
<img src="~static/favicon.png" alt="">
|
||||
<img src="~/static/icon_white.png" alt="">
|
||||
</div>
|
||||
<div class="name">
|
||||
<!-- customer name -->
|
||||
<p>هیما</p>
|
||||
<p>اراک ریل</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="language">
|
||||
<div class="admin-language">
|
||||
<select v-model="selectedLocale">
|
||||
<option v-for="item in locale" :value="item.value">{{item.name}}</option>
|
||||
</select>
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="panel mb-3">
|
||||
<div class="admin-panel mb-3">
|
||||
<slot/>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="col-12 mb-3">
|
||||
<div class="row align-items-center justify-content-end title">
|
||||
<div class="row align-items-center justify-content-end admin-title-bar">
|
||||
<h2>{{title}}</h2>
|
||||
<slot/>
|
||||
</div>
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="container-fluid">
|
||||
<div class="user row align-items-center justify-content-lg-start">
|
||||
<div class="admin-user row align-items-center justify-content-lg-start">
|
||||
<el-avatar :size="50" :src="avatar"></el-avatar>
|
||||
<h2>{{user}}</h2>
|
||||
</div>
|
||||
+1
-5
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="admin" v-if="$auth.loggedIn && $auth.user.scope.includes('admin')">
|
||||
<!-- <div class="admin">-->
|
||||
<!-- <div class="admin">-->
|
||||
<div class="admin">
|
||||
<admin-header/>
|
||||
<div class="container-fluid">
|
||||
@@ -40,10 +40,6 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@import "assets/admin/css/bootstrap-grid-customized.css";
|
||||
@import "assets/admin/fonts/fontawesome/css/all.min.css";
|
||||
</style>
|
||||
<style lang="scss">
|
||||
@import "assets/admin/sass/admin";
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
export default function ({$auth, redirect}) {
|
||||
if ($auth.loggedIn && $auth.user.scope.includes('admin')) return true
|
||||
else return redirect('/admin/login')
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
export default function (ctx) {
|
||||
if (ctx.app.store.state.global.navigation_guard) {
|
||||
ctx.app.store.commit('global/navigationGuards', false)
|
||||
|
||||
/////////////////////////////////// beforeEach
|
||||
|
||||
|
||||
////////////////////////////////// afterEach
|
||||
ctx.app.router.afterEach((to, from) => {
|
||||
if (to.params.lang === 'fa') {
|
||||
$('html').attr({lang: 'fa'})
|
||||
} else if (to.params.lang === 'en') {
|
||||
$('html').attr({lang: 'en'})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
+8
-8
@@ -29,14 +29,13 @@ export default {
|
||||
// Plugins to run before rendering page (https://go.nuxtjs.dev/config-plugins)
|
||||
plugins: [
|
||||
'@/plugins/element-ui',
|
||||
'@/plugins/ckEditor.client',
|
||||
'@/plugins/datePicker.client',
|
||||
'@/plugins/gsap'
|
||||
],
|
||||
|
||||
// Auto import components (https://go.nuxtjs.dev/config-components)
|
||||
components: [
|
||||
'~/components',
|
||||
{path: '~/components/admin', prefix: 'admin'}
|
||||
],
|
||||
components: true,
|
||||
|
||||
// Modules for dev and build (recommended) (https://go.nuxtjs.dev/config-modules)
|
||||
buildModules: [],
|
||||
@@ -60,7 +59,7 @@ export default {
|
||||
build: {
|
||||
transpile: [/^element-ui/],
|
||||
vendor: ["jquery"],
|
||||
plugins: [new webpack.ProvidePlugin({$: "jquery"})],
|
||||
plugins: [new webpack.ProvidePlugin({$: "jquery"})]
|
||||
},
|
||||
router: {
|
||||
middleware: ['redirects'],
|
||||
@@ -70,15 +69,16 @@ export default {
|
||||
host: '0.0.0.0',
|
||||
port: 7320
|
||||
},
|
||||
serverMiddleware: ['~/api/index'],
|
||||
auth: {
|
||||
rewriteRedirects: true,
|
||||
redirect: false,
|
||||
strategies: {
|
||||
local: {
|
||||
endpoints: {
|
||||
login: {url: '/api/auth/user/login', method: 'post', propertyName: 'token'},
|
||||
logout: {url: '/api/auth/user/logout', method: 'post'},
|
||||
user: {url: '/api/auth/user/user', method: 'get', propertyName: 'user'}
|
||||
login: {url: '/api/auth/admin/login', method: 'post', propertyName: 'token'},
|
||||
logout: {url: '/api/auth/admin/logout', method: 'post'},
|
||||
user: {url: '/api/auth/admin/user', method: 'get', propertyName: 'user'}
|
||||
},
|
||||
tokenRequired: true,
|
||||
tokenType: '',
|
||||
|
||||
Generated
+8
@@ -12162,6 +12162,14 @@
|
||||
"resolved": "https://registry.npmjs.org/vue-no-ssr/-/vue-no-ssr-1.1.1.tgz",
|
||||
"integrity": "sha512-ZMjqRpWabMPqPc7gIrG0Nw6vRf1+itwf0Itft7LbMXs2g3Zs/NFmevjZGN1x7K3Q95GmIjWbQZTVerxiBxI+0g=="
|
||||
},
|
||||
"vue-persian-datetime-picker": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/vue-persian-datetime-picker/-/vue-persian-datetime-picker-2.4.1.tgz",
|
||||
"integrity": "sha512-q/Vz/9aen5THRuc9szQwxh1D75bLz8plkakGLimpL5Bg2AATr7uDWzywCjJ8nBkPj0Ddz26d0UksR9dUDB7Tkw==",
|
||||
"requires": {
|
||||
"moment-jalaali": "^0.9.2"
|
||||
}
|
||||
},
|
||||
"vue-router": {
|
||||
"version": "3.4.9",
|
||||
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.4.9.tgz",
|
||||
|
||||
+2
-1
@@ -30,7 +30,8 @@
|
||||
"mongoose": "^5.10.15",
|
||||
"nodemon": "^2.0.6",
|
||||
"nuxt": "^2.14.6",
|
||||
"slick-carousel": "^1.8.1"
|
||||
"slick-carousel": "^1.8.1",
|
||||
"vue-persian-datetime-picker": "^2.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"node-sass": "^4.14.1",
|
||||
|
||||
+26
-10
@@ -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
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -0,0 +1,4 @@
|
||||
import Vue from 'vue'
|
||||
import CKEditor from 'ckeditor4-vue'
|
||||
|
||||
Vue.use(CKEditor)
|
||||
@@ -0,0 +1,4 @@
|
||||
import Vue from 'vue'
|
||||
import datePicker from 'vue-persian-datetime-picker'
|
||||
|
||||
Vue.component('date-picker', datePicker)
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
+8
-4
@@ -468,7 +468,8 @@ export const state = () => ({
|
||||
t2: 'شرکت اراک ریل',
|
||||
t3: 'طراحی و تولید گریتینگ به روشهای الکتروفورج، پرسی و جوش GMAW',
|
||||
t4: 'با ما در ارتباط باشید',
|
||||
t5: 'تماس با ما'
|
||||
t5: 'تماس با ما',
|
||||
t6: 'تاربخ اجرا: '
|
||||
},
|
||||
en: {
|
||||
hero: 'Projects',
|
||||
@@ -476,7 +477,8 @@ export const state = () => ({
|
||||
t2: 'ArakRail Company',
|
||||
t3: 'Design and production of grating by electrophoresis, pressing and welding methods GMAW',
|
||||
t4: 'Get in touch with us',
|
||||
t5: 'Contact Us'
|
||||
t5: 'Contact Us',
|
||||
t6: 'Execution date: '
|
||||
}
|
||||
},
|
||||
blog: {
|
||||
@@ -528,7 +530,8 @@ export const state = () => ({
|
||||
t10: 'شماره تلفن',
|
||||
t11: 'ایمیل',
|
||||
t12: 'پیام',
|
||||
t13: 'ارسال'
|
||||
t13: 'ارسال',
|
||||
t14: 'پیام شما با موفقیت ارسال شد'
|
||||
},
|
||||
en: {
|
||||
hero: 'Contact Us',
|
||||
@@ -544,7 +547,8 @@ export const state = () => ({
|
||||
t10: 'Phone Number',
|
||||
t11: 'Email',
|
||||
t12: 'Message',
|
||||
t13: 'Send'
|
||||
t13: 'Send',
|
||||
t14: 'Your message sent successfully'
|
||||
}
|
||||
},
|
||||
gTech: {
|
||||
|
||||
Reference in New Issue
Block a user