feat: add ci cd files dont edit those files

This commit is contained in:
mahyargdz
2024-10-21 10:22:26 +03:30
commit fb5b440d42
321 changed files with 188273 additions and 0 deletions
+105
View File
@@ -0,0 +1,105 @@
<template>
<div class="archive-page">
<div class="container">
<LineTxt label="آرشیو"/>
<!-- <div class="col-12 col-md-3 mb-3 stretch" v-for="item in archive.docs" :key="item._id" v-if="archive.docs.length">-->
<!-- <div class="news-card justifyBetween">-->
<!-- <img :src="item.thumbCover" :alt="item.title">-->
<!-- <h2>{{ item.title }}</h2>-->
<!-- <nuxt-link :to="{name: 'portal-news-details',params: {portal: currentPortal,details: item.title}}">-->
<!-- <div class="whole-wrapper">-->
<!-- <span class="whole-wrapper-date">{{-->
<!-- jData2(item.customDate) + ' ' + jData(item.customDate)-->
<!-- }}</span>-->
<!-- <span class="whole-wrapper-title"> ادامه مطلب<i class="fas fa-chevron-left"></i></span>-->
<!-- </div>-->
<!-- </nuxt-link>-->
<!-- </div>-->
<!-- </div>-->
<div class="row align-items-stretch">
<template v-if="archive.docs.length">
<NewsBox v-for="item in archive.docs" :key="item._id" :item="item"/>
</template>
<div class="not-found" v-else>
<p>موردی وجود ندارد!</p>
</div>
</div>
<div class="paginate">
<div class="row">
<div class="col-12">
<el-pagination
layout="prev, pager, next"
v-if="archive.totalPages > 1"
class="el-pagination"
@current-change="pageNumber"
:current-page="Number($route.query.page)"
:page-count="Number(archive.totalPages)"
>
</el-pagination>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import moment from "moment-jalaali";
export default {
data() {
return {
archive: null
}
},
computed: {
currentPortal() {
return this.$route.params.portal
},
pageQuery() {
return this.$route.query.page
},
query() {
return this.$route.query
}
},
watch: {
pageQuery(newVal, oldVal) {
this.$nuxt.refresh()
}
},
methods: {
jData(data) {
return moment(data).locale('fa').format('LL')
},
jData2(data) {
return moment(data).locale('fa').fromNow()
},
pageNumber(val) {
if(this.query.flag === 'all')
this.$router.push({name: 'portal-archive', params: {portal: this.currentPortal}, query: {flag: 'all' ,page: val}})
else
this.$router.push({name: 'portal-archive', params: {portal: this.currentPortal}, query: {flag: 'category', catId: this.query.catId ,page: val}})
},
},
async asyncData({$axios, error, params, query}) {
const portalQuery = params.portal
try {
const archive = await $axios.get(`/api/public/getNews?flag=${query.flag}&catId=${query.catId || ''}&portal=${portalQuery}&page=${query.page}`)
return {
archive: archive.data
}
} catch (e) {
error({status: 500, message: "مشکلی پیش آمده است!"})
}
}
}
</script>
+643
View File
@@ -0,0 +1,643 @@
<template>
<div class="category">
<!----------------------Page Top Button----------------------------->
<section class="s1">
<div class="container">
<div class="row">
<div class="col-12 top-btns" v-if="btnsLength > 1">
<div class="mt-2 view-link" v-if="category.category.hasNewsTab">
<button
@click="setChangeInPage({id: $route.query.id ,type: 'news', page: 1})"
class="btn bigBtn btn-primary"
:class="type === 'news' && 'btn-active'"
>
<span>اخبار</span>
</button>
</div>
<div class="mt-2 view-link" v-if="category.category.hasNewsFileTab">
<button
@click="setChangeInPage({id: $route.query.id ,type: 'newsFile'})"
class="btn bigBtn btn-primary"
:class="type === 'newsFile' && 'btn-active'"
>
<span>پرونده خبری</span>
</button>
</div>
<div class="mt-2 view-link" v-if="category.category.hasContentTab">
<button
@click="setChangeInPage({id: $route.query.id ,type: 'content'})"
class="btn bigBtn btn-primary"
:class="type === 'content' && 'btn-active'"
>
<span>درباره ی ...</span>
</button>
</div>
<div class="mt-2 view-link" v-if="category.category.hasMediaTab">
<button
@click="setChangeInPage({id: $route.query.id ,type: 'gallery', galleryType: 'image',page: 1})"
class="btn bigBtn btn-primary"
:class="type === 'gallery' && 'btn-active'"
>
<span>چند رسانه ای</span>
</button>
</div>
<div class="mt-2 view-link" v-if="category.category.hasSubMenusTab">
<button
@click="setChangeInPage({id: $route.query.id ,type: 'subMenu'})"
class="btn bigBtn btn-primary"
:class="type === 'subMenu' && 'btn-active'"
>
<span>صفحات مرتبط</span>
<!-- <span>{{ category.category.title }}</span>-->
</button>
</div>
<div class="mt-2 view-link" v-if="category.category.hasTermsTab">
<button
@click="setChangeInPage({id: $route.query.id ,type: 'terms'})"
class="btn bigBtn btn-primary"
:class="type === 'terms' && 'btn-active'"
>
<span>قوانین و دستوالعمل ها</span>
</button>
</div>
<div class="mt-2 view-link" v-if="category.category.hasNazarTab">
<button
@click="setChangeInPage({id: $route.query.id ,type: 'survey'})"
class="btn bigBtn btn-primary"
:class="type === 'survey' && 'btn-active'"
>
<span>نظر سنجی</span>
</button>
</div>
<div class="mt-2 view-link" v-if="category.category.hasNotificationsTab">
<button
@click="setChangeInPage({id: $route.query.id,type: 'event'})"
class="btn bigBtn btn-primary"
:class="type === 'event' && 'btn-active'"
>
<span>اطلاعیه ها</span>
</button>
</div>
<div class="mt-2 view-link" v-if="category.category.hasSpecNewsTab">
<button
@click="setChangeInPage({id: $route.query.id,type: 'special'})"
class="btn bigBtn btn-primary"
:class="type === 'special' && 'btn-active'"
>
<span>مطالب ویژه</span>
</button>
</div>
</div>
</div>
</div>
</section>
<div class="container">
<div class="row">
<main class="col-12 main-content" :class="(noSideBar && type !== 'gallery') && 'col-lg-9'">
<!-------------------------------News Category------------------------->
<section class="s2" v-if="type === 'news'">
<LineTxt :label="` اخبار ${category.category.title}`"/>
<div class="sectionStyle" v-if="category.news.docs.length">
<template>
<!-- <div class="heronews" v-if="category.heroNews">-->
<!-- <div class="title-holder">-->
<!-- <div class="row">-->
<!-- <div class="col-12 col-md-6 view-img">-->
<!-- <img class="image" :src="category.heroNews.thumbCover" :alt="category.heroNews.title">-->
<!-- </div>-->
<!-- <div class="col-12 col-md-6">-->
<!-- <h2 class="title" :title="category.heroNews.title">{{ category.heroNews.title }}</h2>-->
<!-- <p class="paragraph" :title="category.heroNews.summaryTitle">{{ category.heroNews.summaryTitle }}</p>-->
<!-- <span class="s1-date">-->
<!-- {{ jData2(category.heroNews.customDate) }}-->
<!-- </span>-->
<!-- <nuxt-link class="btn btn-primary" :to="{name: 'portal-news-details',params: {portal: currentPortal,details: category.heroNews.title}}">ادامه مطلب</nuxt-link>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<CategoryHeroNews v-if="category.heroNews" :data="category.heroNews"/>
<CategoryHeroNews v-else :data="category.news.docs[0]"/>
<!-- <div class="heronews" v-else>-->
<!-- <div class="title-holder">-->
<!-- <div class="row">-->
<!-- <div class="col-12 col-md-6 view-img">-->
<!-- <img class="image" :src="category.news.docs[0].thumbCover" :alt="category.news.docs[0].title">-->
<!-- </div>-->
<!-- <div class="col-12 col-md-6">-->
<!-- <h2 class="title" :title="category.news.docs[0].title">{{ category.news.docs[0].title }}</h2>-->
<!-- <p class="paragraph" :title="category.news.docs[0].summaryTitle">{{ category.news.docs[0].summaryTitle }}</p>-->
<!-- <span class="s1-date">-->
<!-- {{ jData2(category.news.docs[0].customDate) }}-->
<!-- </span>-->
<!-- <nuxt-link class="btn btn-primary" :to="{name: 'portal-news-details',params: {portal: currentPortal,details: category.news.docs[0].title}}">ادامه مطلب</nuxt-link>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<div class="list-news">
<div class="mt-3 mb-4">
<div class="line"></div>
</div>
<div class="row">
<NewsBox v-for="(item,index) in category.news.docs" :key="item._id" v-if="category.heroNews || index > 0" :item="item" :timeIsAgo="false"/>
<!-- ******************************************* old style ******************************************* -->
<!-- <div class="col-12 col-sm-6 col-lg-3 mb-5 stretch" v-for="item in category.news.docs" :key="item._id">-->
<!-- <div class="news-card justifyBetween">-->
<!-- <img :src="item.thumbCover" :alt="item.title">-->
<!-- <h2>{{ item.title }}</h2>-->
<!-- <nuxt-link :to="{name: 'portal-news-details',params: {portal: currentPortal,details: item.title}}">-->
<!-- <div class="whole-wrapper">-->
<!-- <span class="whole-wrapper-date">-->
<!-- {{ jData2(item.customDate) + ' ' + jData(item.customDate) }}-->
<!-- </span>-->
<!-- <span class="whole-wrapper-title"> ادامه مطلب<i class="fas fa-chevron-left"></i> </span>-->
<!-- </div>-->
<!-- </nuxt-link>-->
<!-- </div>-->
<!-- </div>-->
<!-- ******************************************* old style ******************************************* -->
</div>
</div>
</template>
</div>
<div class="not-found" v-else>
<p>موردی وجود ندارد!</p>
</div>
<div class="paginate">
<div class="row">
<div class="col-12">
<el-pagination
layout="next, pager, prev"
v-if="paginate"
class="el-pagination"
@current-change="newsPageNumber"
:current-page="Number($route.query.page)"
:page-count="Number(category.news.totalPages)"
>
</el-pagination>
</div>
</div>
</div>
</section>
<!-------------------------------Child Category------------------------->
<section class="s3" v-if="type === 'subMenu'">
<LineTxt :label="` صفحات مرتبط با ${category.category.title}`"/>
<div class="link" v-if="category.category.childs.length">
<ul>
<nuxt-link
v-for="item in category.category.childs"
:key="item._id"
class="btn bigBtn btn-primary"
:to="{name: 'portal-category-details',params: {portal: currentPortal,details: item.title},query: {type: 'news',page: 1, id: item._id}}" v-slot="{navigate,href,isActive}" custom
exact>
<li @click="navigate">
<a :href="href">{{ item.title }}</a>
</li>
</nuxt-link>
</ul>
</div>
<div class="not-found" v-else>
<p>موردی وجود ندارد!</p>
</div>
</section>
<!-----------------------------Page Gallery--------------------------->
<CategoryGallerySection
v-if="type === 'gallery'"
:url="url"
:setChangeInPage="setChangeInPage"
:galleryType="galleryType"
:media="media"
:category="category"
:pageNumber="pageNumber"
:key="galleryComponentKey"
/>
<!-----------------------------Page content--------------------------->
<section class="s5" v-if="type === 'content'">
<LineTxt :label="` درباره ${category.category.title}`"/>
<div class="view-page-content ck-content" v-html="category.category.pageContent"
v-if="category.category.pageContent.length"></div>
<div class="not-found" v-else>
<p>موردی وجود ندارد!</p>
</div>
</section>
<!-----------------------------Page Terms--------------------------->
<section class="s6" v-if="type === 'terms'">
<LineTxt :label="` قوانین و دستورالعمل ها ${category.category.title}`"/>
<div class="row">
<div class="col-12 view-page-terms" v-for="item in category.category.terms" :key="item._id">
<div class="view-item-terms">
<div class="view-title-terms">
<i class="far fa-folder-open"></i>
<h3 :title="item.title">{{ item.title }}</h3>
</div>
<div>
<a class="btn btn-primary" :href="item.file" target="_blank">مطالعه کنید</a>
<a class="btn btn-primary" :href="item.file" target="_blank" download>دانلود</a>
</div>
</div>
</div>
</div>
<div class="not-found" v-if="!category.category.terms.length">
<p>موردی وجود ندارد!</p>
</div>
</section>
<!-----------------------------Page Survey--------------------------->
<section class="s7" v-if="type === 'survey'">
<LineTxt :label="` نظرسنجی ${category.category.title}`"/>
<div class="view-page-survey" v-for="item in category.polls" :key="item._id">
<div class="survey-item1">
<h2>{{ item.title }}</h2>
<p class="about-title">درباره نظر سنجی :</p>
<p class="about-txt">{{ item.description }}</p>
</div>
<div class="row survey-item2" v-if="!item.userIds.includes(userToken)">
<div class="col-12 col-md-6 mb-3">
<el-radio-group v-model="radio" v-for="(itemSelect, index) in item.options" :key="index"
v-if="item.surveyType === 'radio'">
<el-radio :label="itemSelect">{{ itemSelect }}</el-radio>
</el-radio-group>
<el-checkbox-group v-model="checkList"
v-if="item.surveyType === 'check'">
<el-checkbox v-for="(itemSelect2, index) in item.options" :key="index" :label="itemSelect2">
{{ itemSelect2 }}
</el-checkbox>
</el-checkbox-group>
</div>
<div class="col-12 col-md-6 comment-btn">
<button @click="post(item._id, item.surveyType)"
class="btn bigBtn btn-primary "
:disabled="item.surveyType === 'check' ? !checkList.length : !radio"
> ثبت نظر
</button>
</div>
</div>
<div class="survey-item2"
v-for="(answerItem, index) in item.options" :key="index"
v-if="item.userIds.includes(userToken)">
<h4>{{ answerItem }}</h4>
<el-progress :percentage="progress(item, answerItem)" color="#CC0000"></el-progress>
</div>
</div>
<div class="not-found" v-if="!category.polls.length">
<p>موردی وجود ندارد!</p>
</div>
</section>
<!-----------------------------Page Survey--------------------------->
<section class="s8" v-if="type === 'event'">
<LineTxt :label="` اطلاعیه ها ${category.category.title}`"/>
<ul>
<nuxt-link
v-for="item in category.events"
:key="item._id"
:to="{name: 'portal-news-details', params: {portal:currentPortal, details: item._id}}"
v-slot="{href,navigate}"
custom
>
<li @click="navigate">
<i class="fas fa-megaphone"></i>
<a :href="href">{{ item.title }}</a>
</li>
</nuxt-link>
</ul>
<div class="not-found" v-if="!category.events.length">
<p>موردی وجود ندارد!</p>
</div>
</section>
<!-----------------------------Page Survey--------------------------->
<section class="s9" v-if="type === 'special'">
<LineTxt :label="` مطالب ویژه ${category.category.title}`"/>
<ul>
<nuxt-link
:to="{name: 'portal-news-details', params: {portal:currentPortal, details: item._id}}"
v-for="item in category.specials"
:key="item._id"
v-slot="{href,navigate}"
>
<li>
<i class="fas fa-sparkles"></i>
<a :href="href">{{ item.title }}</a>
</li>
</nuxt-link>
</ul>
<div class="not-found" v-if="!category.specials.length">
<p>موردی وجود ندارد!</p>
</div>
</section>
<!-----------------------------Page Terms--------------------------->
<section class="s10" v-if="type === 'newsFile'">
<div class="container">
<LineTxt :label="` پرونده خبری ${category.category.title}`"/>
<div class="row">
<div class="col-12 view-page-newsFile" v-for="(item, index) in category.newsFile"
:key="item._id"
>
<div class="view-item-newsFile">
<nuxt-link :to="{name: 'portal-newsfile-details', params: {portal:currentPortal, details: item.title}, query: { page: 1 }}" class="view-title-newsFile">
<span>{{ index + 1 }}</span>
<h3>{{ item.title }}</h3>
</nuxt-link>
</div>
</div>
</div>
<div class="not-found" v-if="!category.newsFile.length">
<p>موردی وجود ندارد!</p>
</div>
</div>
</section>
</main>
<!-- <aside class="col-lg-3 d-none side-bar" :class="noSideBar && 'd-lg-block'"-->
<!-- v-if="type === 'gallery'">-->
<!-- <div-->
<!-- class="managerInfo sideBarItem"-->
<!-- v-if="category.category.hasManagerInfo"-->
<!-- :class="type === 'gallery' && 'galleryPage'"-->
<!-- >-->
<!-- <SideBarLineTxt label="برگزیده ها"/>-->
<!-- <div class="sectionStyle" v-for="(item,index) in media.favorites" :key="item._id + 1" v-if="index < 3">-->
<!-- <img :src="item.cover" :alt="item.title">-->
<!-- <nuxt-link class="view-title" :to="url(item.title)" :title="item.title">-->
<!-- <div class="title">-->
<!-- <h4>{{ item.title }}</h4>-->
<!-- </div>-->
<!-- </nuxt-link>-->
<!-- </div>-->
<!-- <div class="not-found" v-if="!media.favorites.length">-->
<!-- <p>موردی وجود ندارد!</p>-->
<!-- </div>-->
<!-- </div>-->
<!-- </aside>-->
<aside class="col-lg-3 d-none side-bar" :class="noSideBar && 'd-lg-block'" v-if="type !== 'gallery'">
<div
class="managerInfo sideBarItem"
v-if="category.category.hasManagerInfo"
:class="type === 'gallery' && 'galleryPage'"
>
<SideBarLineTxt label="معرفی مدیر"/>
<div class="sectionStyle">
<img :src="category.category.managerCover" :alt="category.category.managerName">
<div class="txtBox">
<h2>{{ category.category.managerName }}</h2>
<p>{{ category.category.managerDescription }}</p>
</div>
</div>
</div>
<div
class="specNews sidebarLinks mt-3 sideBarItem"
v-if="category.specials.length"
:class="type === 'gallery' && !category.category.hasManagerInfo && 'galleryPage'"
>
<SideBarLineTxt label="مطالب ویژه"/>
<div class="sectionStyle">
<!-- <ul>-->
<!-- <li v-for="(item,index) in category.specials" :key="item._id + 1" v-if="index < 4">-->
<!-- <nuxt-link :to="{name: 'portal-news-details', params: {portal: currentPortal,details: item.title}}" :title="item.title">-->
<!-- <i class="fas fa-sparkles"></i>-->
<!-- <span>{{ item.title }}</span>-->
<!-- </nuxt-link>-->
<!-- </li>-->
<!-- </ul>-->
<div id="slides-spec">
<nuxt-link
v-for="(item,index) in category.specials"
:key="item._id + 1"
v-if="index < 4"
:to="{name: 'portal-news-details', params: {portal: currentPortal,details: item._id}}"
v-slot="{href,navigate}"
custom
>
<div @click="navigate" class="slide pointer" :title="item.title">
<img :src="item.cover" :alt="item.title">
<a :href="href">{{ item.title }}</a>
</div>
</nuxt-link>
</div>
</div>
</div>
<div
class="notifications sidebarLinks mt-3 sideBarItem"
v-if="category.events.length"
:class="type === 'gallery' && !category.category.hasManagerInfo && !category.specials.length && 'galleryPage'"
>
<SideBarLineTxt label="اطلاعیه ها"/>
<div class="sectionStyle">
<ul>
<li v-for="(item,index) in category.events" :key="item._id + 2" v-if="index < 4">
<nuxt-link :to="{name: 'portal-news-details', params: {portal: currentPortal,details: item._id}}" :title="item.title">
<i class="fal fa-megaphone"></i>
<span>{{ item.title }}</span>
</nuxt-link>
</li>
</ul>
</div>
</div>
<div
class="latestNews sidebarLinks mt-3 sideBarItem"
v-if="category.events.length"
:class="type === 'gallery' && !category.category.hasManagerInfo && !category.specials.length && !category.events.length && 'galleryPage'"
>
<SideBarLineTxt label="آخرین اخبار"/>
<div class="sectionStyle">
<ul>
<li v-for="item in category.latestNews" :key="item._id + 3">
<nuxt-link :to="{name: 'portal-news-details', params: {portal: currentPortal,details: item._id}}" :title="item.title">
<i class="fas fa-circle"></i>
<span>{{ item.title }}</span>
</nuxt-link>
</li>
</ul>
</div>
</div>
</aside>
</div>
</div>
</div>
</template>
<script>
if (process.client) require("slick-carousel")
import moment from "moment-jalaali"
export default {
data() {
return {
category: null,
terms: [],
survey: [],
media: null,
radio: null,
checkList: [],
galleryComponentKey: 0
}
},
computed: {
paginate() {
return this.category.news.totalPages > 1
},
currentPortal() {
return this.$route.params.portal
},
pageQuery() {
return this.$route.query.page
},
type() {
return this.$route.query.type
},
galleryType() {
return this.$route.query.galleryType
},
btnsLength() {
let count = 0
if (this.category.category.hasNewsTab) count++
if (this.category.category.hasContentTab) count++
if (this.category.category.hasMediaTab) count++
if (this.category.category.hasSubMenusTab) count++
if (this.category.category.hasTermsTab) count++
if (this.category.category.hasNotificationsTab) count++
if (this.category.category.hasSpecNewsTab) count++
if (this.category.category.hasNazarTab) count++
return count
},
userToken() {
return this.$store.state.front.pollToken
},
noSideBar() {
return this.category.category.hasManagerInfo || this.category.specials?.length || this.category.events?.length
}
},
watch: {
pageQuery(newVal, oldVal) {
this.$nuxt.refresh()
},
galleryType(newVal, oldVal) {
this.$nuxt.refresh()
},
type(newVal, oldVal) {
},
media(newVal, oldVal) {
this.galleryComponentKey = Math.random()
},
},
methods: {
url(title) {
if (this.galleryType === 'image') {
return {name: 'portal-gallery-media', params: {portal: this.currentPortal, media: title}}
}
if (this.galleryType === 'video') {
return {name: 'portal-videos-video', params: {portal: this.currentPortal, video: title}}
}
if (this.galleryType === 'graphic') {
return {name: 'portal-graphics-graphic', params: {portal: this.currentPortal, graphic: title}}
}
},
pageNumber(val) {
this.$router.push({
name: 'portal-category-details',
params: {portal: this.currentPortal, details: this.$route.params.details},
query: {type: 'gallery', galleryType: this.galleryType, page: val, id: this.$route.query.id}
})
$(window).scrollTop(0)
},
newsPageNumber(val) {
this.$router.push({
name: 'portal-category-details',
params: {portal: this.currentPortal, details: this.$route.params.details},
query: {type: 'news', page: val, id: this.$route.query.id}
})
$(window).scrollTop(0)
},
jData(data) {
return moment(data).locale('fa').format('LL')
},
jData2(data) {
return moment(data).locale('fa').fromNow()
},
setChangeInPage(query) {
this.$router.push({name: 'portal-category-details', params: {portal: this.currentPortal, details: this.$route.params.details, id: this.$route.params.id}, query: query})
},
post(id, type) {
this.$axios.post('/api/public/answer', {
surveyId: id,
option: type === 'radio' ? [this.radio] : this.checkList,
pollToken: this.$store.state.front.pollToken
})
.then(res => {
this.$nuxt.refresh()
this.$message({
type: 'success',
message: 'نظر شما با موفقیت ثبت شد'
})
})
.catch(e => {
console.log(e)
})
},
progress(item, answerItem) {
let filteredAnswers = item.answers.filter(item0 => item.options.includes(item0))
let num = filteredAnswers.filter(item1 => item1 === answerItem).length
return Number(((num * 100 / filteredAnswers.length) || 0).toFixed(0))
}
},
mounted() {
$(document).ready(() => {
$("#slides-spec").slick({
dots: true,
slidesToShow: 1,
rtl: true,
autoplay: true,
autoplaySpeed: 3000,
speed: 1000,
arrows: false,
infinite: false,
pauseOnHover: true
})
})
},
async asyncData({$axios, params, error, query}) {
try {
const request = [
$axios.get(`/api/public/getCategory/${encodeURIComponent(params.details)}?page=${query.page}`),
$axios.get(`/api/public/getGalleryCat/${query.id}?type=${query.galleryType}&page=${query.page}`)
]
const fetch = await Promise.all(request)
const [category, media] = fetch
return {
category: category.data,
media: media.data
}
} catch (e) {
console.log('e', e)
error({status: 404, message: 'مشکلی پیش آمده است!'})
}
}
}
</script>
+197
View File
@@ -0,0 +1,197 @@
<template>
<div class="contact-page">
<div class="container">
<div class="row">
<main class="col-12 col-right">
<section class="s1-right">
<div class="row">
<div class="col-12 col-lg-6 s1-col1-right">
<h2 class="s1-col1-title">تماس با ما</h2>
<p class="s1-col1-desc">برای ارتباط با ما میتوانید از طریق فرم زیر اقدام نمایید</p>
<form @submit.prevent="post">
<div class="formRow" :class="validation.name ? 'err' : null">
<input v-model="message.name" class="input" name="name" type="text"
placeholder="نام و نام خانوادگی خود را وارد کنید"/>
<p v-if="validation.name">{{ validation.name.msg }}</p>
</div>
<div class="formRow" :class="validation.email ? 'err' : null">
<input v-model="message.email" class="input" name="email" type="text" placeholder="ایمیل خود را وارد کنید"/>
<p v-if="validation.email">{{ validation.email.msg }}</p>
</div>
<div class="formRow" :class="validation.description ? 'err' : null">
<textarea v-model="message.description" name="description" class="input" rows="4" placeholder="توضیحات خود را وارد کنید"></textarea>
<p v-if="validation.description">{{ validation.description.msg }}</p>
</div>
<div class="row view-captcha">
<div class="formRow" :class="validation.captcha ? 'err' : null">
<input v-model="message.captcha" class="input" name="captcha" type="text" placeholder="متن داخل عکس را وارد کنید"/>
</div>
<div class="new-captcha">
<div class="captcha" v-html="captcha"></div>
<button @click="reloadCaptcha" type="button" class="btn btn-primary">
<i class="fas fa-sync-alt"></i>
</button>
</div>
<p class="err-captcha" v-if="validation.captcha">{{ validation.captcha.msg }}</p>
</div>
<div class="btnSub">
<button class="btn-link" type="submit">ارسال</button>
<!-- <nuxt-link >SUBMIT NOW</nuxt-link> -->
</div>
</form>
</div>
<div class="col-12 col-lg-6 mt-5 mt-lg-0 s1-col2-right">
<div class="mapouter">
<div class="bg-map"></div>
<div class="gmap_canvas">
<iframe id="gmap_canvas"
src="https://maps.google.com/maps?q=%D8%A7%D8%B3%D8%AA%D8%A7%D9%86%D8%AF%D8%A7%D8%B1%DB%8C%20%D9%85%D8%B1%DA%A9%D8%B2%DB%8C&t=&z=13&ie=UTF8&iwloc=&output=embed"
frameborder="0"
scrolling="no" marginheight="0" marginwidth="0"></iframe>
<a href="https://fmovies2.org"></a><br>
</div>
</div>
</div>
</div>
</section>
<section class="s2-right">
<div class="row">
<div class="col-12 col-md-4">
<div class="s2-right-title">
<i class="far fa-envelope"></i>
<h4>ایمیل</h4>
</div>
<a class="s2-right-desc email" :href="`mailto: ${yearBanner.email}`">{{ yearBanner.email }}</a>
</div>
<div class="col-12 col-md-4">
<div class="s2-right-title">
<i class="far fa-map-marker-alt"></i>
<h4>آدرس</h4>
</div>
<p class="s2-right-desc">اراک ، بلوار فاطمیه ، استانداری مرکزی</p>
</div>
<div class="col-12 col-md-4">
<div class="s2-right-title">
<i class="far fa-phone-alt"></i>
<h4>تلفن</h4>
</div>
<a class="s2-right-desc phone" href="tel:08633442222">086-33442222</a>
</div>
</div>
</section>
<!-- <section class="s3-right" v-if="info.docs.length">-->
<!-- &lt;!&ndash; <div class="s3-right-view-title">&ndash;&gt;-->
<!-- &lt;!&ndash; <h1 class="s3-right-title"></h1>&ndash;&gt;-->
<!-- &lt;!&ndash; <div class="br"></div>&ndash;&gt;-->
<!-- &lt;!&ndash; </div>&ndash;&gt;-->
<!-- <LineTxt label="مطالب ویژه"/>-->
<!-- <div class="s3-right-item">-->
<!-- <div class="row">-->
<!-- <div class="col-12 col-md-3" v-for="(item, index) in info.docs" :key="item._id">-->
<!-- <nuxt-link class="s3-right-title" :to="{name: 'portal-news-details', params: {portal: currentPortal, details: item.title}}" :title="item.title">-->
<!-- <p>{{ index + 1 }}</p>-->
<!-- <h4>{{ item.title }}</h4>-->
<!-- </nuxt-link>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </section>-->
</main>
<!-- <aside class="d-none d-lg-block col-lg-3 col-left">-->
<!-- <div class="cover" v-for="(item,index) in news.docs" :key="item._id" v-if="index < 4">-->
<!-- <nuxt-link :to="{name: 'portal-news-details', params: {portal: currentPortal, details: item.title}}" :title="item.title">-->
<!-- <img :src="item.thumbCover" :alt="item.title">-->
<!-- <p>{{ item.title }}</p>-->
<!-- </nuxt-link>-->
<!-- </div>-->
<!-- </aside>-->
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
captcha: null,
message: {
name: '',
email: '',
description: '',
captcha: '',
modelName: 'contactus'
},
validation: {},
info: null,
news: null
}
},
methods: {
reloadCaptcha() {
this.$axios.get('/api/public/getCaptcha').then(res => {
this.captcha = res.data
})
},
post() {
this.validation = {}
this.$axios.post('/api/public/addComment', this.message)
.then(res => {
this.reloadCaptcha()
this.$message({
type: 'success',
message: 'پیام شما با موفقیت ارسال شد'
})
this.message = {
name: '',
email: '',
description: '',
captcha: '',
modelName: 'contactus'
}
})
.catch(e => {
this.reloadCaptcha()
if (e.response.status === 422) this.validation = e.response.data.validation
else console.log(e)
})
}
},
computed: {
currentPortal() {
return this.$route.params.portal
},
yearBanner() {
return this.$store.state.front.yearBanner
}
},
async asyncData({$axios, error, params}) {
try {
const request = [
$axios.get('/api/public/getCaptcha'),
// $axios.get(`/api/public/getNews?flag=special&portal=${params.portal}`),
// $axios.get(`/api/public/getNews?flag=new&portal=${params.portal}`)
]
let fetch = await Promise.all(request)
const [captcha, info, news] = fetch
return {
// info: info.data,
captcha: captcha.data,
// news: news.data
}
} catch (e) {
error({status: 500, message: 'دریافت اطلاعات با مشکل مواجه شد!'})
}
}
}
</script>
+242
View File
@@ -0,0 +1,242 @@
<template>
<div class="container">
<div class="content">
<img :src="imageUrl" class="bookCover" alt="" @click="openBook(1)" />
<div class="frameBox" v-show="showFrame">
<iframe
src="https://ostandari-library.run.danakcorp.com/"
id="frame"
class="frame"
frameborder="0"
></iframe>
<svg
@click="closeBook"
width="40"
height="40"
viewBox="0 0 24 24"
fill="rgb(255,120,60)"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 22C17.5 22 22 17.5 22 12C22 6.5 17.5 2 12 2C6.5 2 2 6.5 2 12C2 17.5 6.5 22 12 22Z"
stroke="#292D32"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M9.16998 14.8299L14.83 9.16992"
stroke="#292D32"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M14.83 14.8299L9.16998 9.16992"
stroke="#292D32"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</div>
</div>
<div class="bookshelf"></div>
</div>
</template>
<script>
import { ref } from "vue";
import { useRoute, useRouter } from "vue-router";
export default {
data() {
return {
showFrame: ref(false),
imageUrl: "https://ostan-mr.ir/uploads/books/tumb.jpg",
imageUrl2: "https://ostan-mr.ir/uploads/books/saramad/saramad-1.png",
message: null,
target: null,
};
},
mounted() {},
methods: {
closeBook() {
this.showFrame = false;
// const iframe = document.querySelector("iframe");
// iframe.contentWindow.postMessage("reset", "*");
},
openBook(value) {
this.showFrame = true;
this.target = value;
this.message = value;
const iframe = document.querySelector("iframe");
iframe.contentWindow.postMessage(this.message, "*");
// $(document).ready(function () {
// $("#frame").flipBook({
// pdfUrl:"/amirkabir.pdf",
// viewMode:'3d',
// // backgroundColor:"#150000",
// backgroundPattern:"images/patterns/woven.png",
// background:'url("images/patterns/woven.png")',
// skin:'dark',
// rightToLeft:true,
// btnZoomIn : {enabled:false},
// btnZoomOut : {enabled:false},
// btnToc : {enabled:false},
// btnShare : {enabled:false},
// btnDownloadPages : {enabled:false},
// btnDownloadPdf : {enabled:false},
// // btnSound : {enabled:false},
// btnPrint : {enabled:false},
// btnBookmark : {enabled:false},
// // btnNext: {enabled:true, icon: 'fa-long-arrow-right', title: 'Next page'},
// // btnPrev: {enabled:true, icon: 'fa-long-arrow-left', title: 'Previouse page'},
// viewMode:'3d',
// skin:'dark',
// menuMargin:10,
// menuBackground:'none',
// menuShadow:'none',
// menuAlignHorizontal:'center',
// menuOverBook:true,
// btnRadius:40,
// btnMargin:4,
// btnSize:14,
// btnPaddingV:16,
// btnPaddingH:16,
// btnBorder:'2px solid rgba(255,255,255,.7)',
// btnBackground:"rgba(0,0,0,.3)",
// btnColor:'rgb(255,120,60)',
// sideBtnRadius:60,
// sideBtnSize:60,
// sideBtnBackground:"rgba(0,0,0,.7)",
// sideBtnColor:'rgb(255,120,60)',
// });
// })
// console.log($('frame2', "#frame2"));
},
},
};
</script>
<style>
.frame3 {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
}
.bookCover {
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
height: 200px;
width: 150px;
z-index: 1;
-webkit-transition: all 0.2s ease;
-moz-transition: all 0.2s ease;
-o-transition: all 0.2s ease;
transition: all 0.2s ease;
}
.bookCover2 {
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
height: 200px;
width: 150px;
z-index: 1;
-webkit-transition: all 0.2s ease;
-moz-transition: all 0.2s ease;
-o-transition: all 0.2s ease;
transition: all 0.2s ease;
}
.bookCover:hover {
cursor: pointer;
-moz-transform: translate(0, -12px);
-webkit-transform: translate(0, -12px);
-o-transform: translate(0, -12px);
-ms-transform: translate(0, -12px);
transform: translate(0, -12px);
-webkit-transition: all 0.2s ease;
-moz-transition: all 0.2s ease;
-o-transition: all 0.2s ease;
transition: all 0.2s ease;
}
.container {
position: relative;
width: 100%;
}
.bookshelf {
position: absolute;
width: 60%;
right: 20%;
height: 100px;
top: 190px !important;
background-image: url("https://storage.ning.com/topology/rest/1.0/file/get/12757027663?profile=RESIZE_1200x");
background-repeat: no-repeat;
background-position: bottom;
background-size: 100%;
overflow: hidden;
}
@media (max-width: 1000px) {
.bookshelf {
width: 90%;
right: 5%;
}
.bookCover {
margin-top: 30px;
}
.bookCover2 {
margin-top: 30px;
}
}
.content {
display: flex;
justify-content: center;
align-items: center;
height: 300px;
gap: 40px;
}
.frameBox {
position: fixed;
z-index: 10;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden !important;
top: 0;
left: 0;
backdrop-filter: blur(2px);
width: 100vw;
height: 100vh;
}
.frameBox svg {
cursor: pointer;
position: absolute;
top: 10px;
right: 30px;
z-index: 10000;
}
.frame {
position: fixed;
display: flex;
justify-content: center;
align-items: center;
top: 0px;
right: 0;
background-color: black;
width: 100vw;
height: 100vh;
max-width: 100vw;
max-height: 100vh;
}
</style>
+124
View File
@@ -0,0 +1,124 @@
<template>
<div class="meeting-page">
<div class="container">
<div class="row">
<div class="col-12">
<LineTxt label="نظرات و پیشنهادات"/>
</div>
<div class="col-12 ">
<div class="view-form">
<form @submit.prevent="post">
<div class="formRow" :class="validation.name ? 'err' : null">
<input class="input" v-model="message.name" name="name" type="text" placeholder="نام و نام خانوادگی خود را وارد کنید"/>
<p v-if="validation.name">{{ validation.name.msg }}</p>
</div>
<div class="formRow" :class="validation.email ? 'err' : null">
<input class="input" v-model="message.email" name="email" type="email" placeholder="ایمیل خود را وارد کنید"/>
<p v-if="validation.email">{{ validation.email.msg }}</p>
</div>
<div class="formRow" :class="validation.phoneNumber ? 'err' : null">
<input class="input" v-model="message.phoneNumber" name="phoneNumber" type="text" placeholder="شماره تماس خود را وارد کنید"/>
<p v-if="validation.phoneNumber">{{ validation.phoneNumber.msg }}</p>
</div>
<div class="formRow" :class="validation.description ? 'err' : null">
<textarea class="input" v-model="message.description" name="description" type="text" placeholder="ایده یا نظر"/>
<p v-if="validation.description">{{ validation.description.msg }}</p>
</div>
<div class="row view-captcha">
<div class="formRow col-12 col-md-6" :class="validation.captcha ? 'err' : null">
<input v-model="message.captcha" class="input" name="captcha" type="text" placeholder="متن داخل عکس را وارد کنید"/>
</div>
<div class="new-captcha col-12 col-md-6">
<div class="captcha" v-html="captcha"></div>
<button @click="reloadCaptcha" type="button" class="btn btn-primary">
<i class="fas fa-sync-alt"></i>
</button>
</div>
<p class="err-captcha" v-if="validation.captcha">{{ validation.captcha.msg }}</p>
</div>
<div class="btnSub">
<button class="btn btn-primary btn-link" type="submit">ثبت</button>
<!-- <nuxt-link >SUBMIT NOW</nuxt-link> -->
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
message: {
name: '',
description: '',
email: '',
phoneNumber: '',
captcha: '',
},
validation: {},
captcha: null
}
},
methods: {
reloadCaptcha() {
this.$axios.get('/api/public/getCaptcha').then(res => {
this.captcha = res.data
})
},
post() {
this.validation = {}
this.$axios.post('/api/public/addFeedBack', this.message)
.then(res => {
this.reloadCaptcha()
this.$message({
type: 'success',
message: 'پیام شما با موفقیت ارسال شد'
})
this.message = {
name: '',
description: '',
email: '',
phoneNumber: '',
captcha: '',
}
})
.catch(e => {
this.reloadCaptcha()
if (e.response.status === 422) this.validation = e.response.data.validation
else console.log(e)
})
}
},
computed: {},
async asyncData({$axios, error, params}) {
try {
const request = [
$axios.get('/api/public/getCaptcha'),
]
let fetch = await Promise.all(request)
const [captcha] = fetch
return {
captcha: captcha.data,
}
} catch (e) {
error({
status: 500, message: 'دریافت اطلاعات با مشکل مواجه شد!'
})
}
}
}
</script>
+197
View File
@@ -0,0 +1,197 @@
<template>
<div class="gallery-details">
<section class="container">
<div class="row">
<div class="col-12 view-date">
<p class="date">{{ jalali(info.customDate || info.created_at) }}</p>
<p class="date">{{ jDate(info.customDate || info.created_at) }}</p>
</div>
<div v-if="info.summaryTitle" class="col-12 col-md-6">
<h2 class="summry-title mt-3">
{{ info.summaryTitle }}
</h2>
</div>
<div class="col-12">
<h1 class="title">
{{ info.title }}
</h1>
</div>
<div v-if="info.leadTitle" class="col-12">
<p class="summry-title mb-4">
{{ info.leadTitle }}
</p>
</div>
<div class="col-12 user-info">
<div class="row">
<div class="col-12 col-md-6">
<span>توسط {{ info._creator.firstName + ' ' + info._creator.lastName }}</span>
<span class="date"> - {{ jDate2(info.customDate || info.created_at) }}</span>
</div>
<div class="col-12 col-md-6 item2">
<el-popover
placement="top-start"
title=""
trigger="hover"
:value="autoPlayNotice"
content="نمایش پشت سرهم تصاویر">
<button class="btn btn-primary" slot="reference" @click="autoPlay"><i class="fas fa-play"></i></button>
</el-popover>
</div>
</div>
</div>
<div class="col-12 mb-4">
<div class="row">
<div class="col-12 img-gallery">
<a :href="info.cover">
<img style="width : 100%" :src="info.thumbCover" alt="">
</a>
</div>
<template v-for="(item , index) in info.images">
<div :key="item._id" class="col-12 col-md-2 mt-4 img-gallery">
<a :href="item">
<img style="width : 100%" :src="info.thumbImages[index]" alt="">
</a>
</div>
</template>
</div>
</div>
</div>
</section>
<section class="s2" v-if="related.length">
<h3>مطالب مرتبط</h3>
<div id="slides">
<nuxt-link
class="slide"
v-for="item in related"
:key="item._id"
:to="{name: 'portal-gallery-media',params: {portal: $route.params.portal,media: item._id}}"
>
<div class="view-txt">
<div>
<p class="h3">{{ item.title }}</p>
<p>{{ item.summaryTitle }}</p>
<div class="date">
<span>{{ jalali(item.customDate || item.created_at) }}</span>
<span>توسط {{ item._creator.firstName + ' ' + item._creator.lastName }}</span>
</div>
</div>
</div>
</nuxt-link>
</div>
</section>
</div>
</template>
<script>
import moment from 'moment-jalaali'
if (process.client) require("slick-carousel")
export default {
data() {
return {
info: null,
galleryShown: false,
autoPlayNotice: false,
initialIndex: 0,
related: []
}
},
mounted() {
setTimeout(() => this.autoPlayNotice = true, 4000)
setTimeout(() => this.autoPlayNotice = false, 7000)
$(document).ready(() => {
new SimpleLightbox('.gallery-details .img-gallery a')
// $('.img-gallery a').simpleLightbox({
//
// });
$("#slides").slick({
dots: true,
slidesToShow: this.related.length === 1 ? 1 : 2,
rtl: true,
responsive: [
{
breakpoint: 960,
settings: {
slidesToShow: 2,
slidesToScroll: 1,
infinite: true,
dots: true
}
},
{
breakpoint: 720,
settings: {
slidesToShow: 2,
slidesToScroll: 1
}
},
{
breakpoint: 540,
settings: {
slidesToShow: 1,
slidesToScroll: 1
}
}
]
})
})
},
methods: {
jalali(date) {
return moment(date).locale('fa').fromNow()
},
jDate(date) {
return moment(date).locale('fa').format('LL')
},
jDate2(date) {
return moment(date).locale('fa').format('a h:mm - jYYYY/jMM/jDD')
},
autoPlay() {
let gallery = new SimpleLightbox('.gallery-details .img-gallery a')
gallery.open()
setInterval(() => gallery.next(), 3000)
}
},
head() {
return {
title: 'جزئیات تصویر',
meta: [
{
hid: 'description',
name: 'description',
content: this.info.summaryTitle
},
{
hid: 'keywords',
name: 'keywords',
content: this.info.keywords
}
]
}
},
async asyncData({params, error, $axios}) {
try {
let info = await $axios.get(`/api/public/getGallery/${encodeURIComponent(params.media)}`)
let related = await $axios.get(`/api/public/getRelatedGallery`, {
params: {
type: 'image',
title: params.media
}
})
return {
info: info.data,
related: related.data
}
} catch (err) {
error({status: 404, message: 'دریافت اطلاعات با مشکل مواجه شده است!'})
}
}
}
</script>
+139
View File
@@ -0,0 +1,139 @@
<template>
<div class="gallery-page">
<div class="container">
<div class="row">
<div class="col-12 col-md-9">
<h3 class="gallery-title">عکس</h3>
<div>
<div class="row">
<div class="col-12 mb-5 sectionStyle">
<div class="gallery-item1" v-if="gallery && gallery.hero">
<nuxt-link :to="{name: 'portal-gallery-media', params: {portal: currentPortal, media: gallery.hero._id}}" class="gallery-img-box1">
<img :src="gallery.hero.thumbCover" alt="" class="gallery-img1">
<div class="gallery-detail-item1">
<h3 class="gallery-detail-title1">{{ gallery.hero.title }}</h3>
<p class="gallery-detail-date1">{{ jDate(gallery.hero.customDate || gallery.hero.created_at) }}</p>
</div>
</nuxt-link>
</div>
<div class="gallery-item1" v-else-if="gallery && gallery.all && gallery.all.docs && gallery.all.docs.length">
<nuxt-link :to="{name: 'portal-gallery-media', params: {portal: currentPortal, media: gallery.all.docs[0]._id}}" class="gallery-img-box1">
<img :src="gallery.all.docs[0].thumbCover" alt="" class="gallery-img1">
<div class="gallery-detail-item1">
<h3 class="gallery-detail-title1">{{ gallery.all.docs[0].title }}</h3>
<p class="gallery-detail-date1">{{ jDate(gallery.all.docs[0].customDate || gallery.all.docs[0].created_at) }}</p>
</div>
</nuxt-link>
</div>
</div>
<div class="col-12" v-if="gallery && gallery.all && gallery.all.docs && !gallery.all.docs.length">
<div class="not-found">
<p>موردی وجود ندارد!</p>
</div>
</div>
<div class="col-12 col-sm-6 col-md-3 mb-3 sectionStyle" v-for="(item, index) in gallery.all.docs" :key="item._id" v-if="index > 0">
<div class="gallery-item">
<nuxt-link :to="{name: 'portal-gallery-media', params: {portal: currentPortal, media: item._id}}" class="gallery-img-box">
<img :src="item.thumbCover" alt="" class="gallery-img">
</nuxt-link>
<div class="gallery-detail-item">
<h3 class="gallery-detail-title">{{ item.title }}</h3>
<p class="gallery-detail-date" id="gallery-detail-date">{{ jDate(item.customDate || item.created_at) }}</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-12 col-md-3">
<h3 class="gallery-side">برگزیده ها</h3>
<div class="sectionStyle" v-if="gallery && gallery.favorites && gallery.favorites.length">
<div class="row">
<div class="col-12 col-sm-6 col-md-12 mb-3" v-for="(item, index) in gallery.favorites" :key="item._id" v-if="index < 5">
<div class="gallery-item ">
<nuxt-link :to="{name: 'portal-gallery-media', params: {portal: currentPortal, media: item._id}}" class="gallery-img-box">
<img :src="item.thumbCover" alt="" class="gallery-img">
</nuxt-link>
<div class="gallery-detail-item">
<h3 class="gallery-detail-title">{{ item.title }}</h3>
<p class="gallery-detail-date" id="gallery-detail-date2">{{ jDate(item.customDate || item.created_at) }}</p>
</div>
</div>
</div>
</div>
</div>
<div class="not-found" v-if="gallery && gallery.favorites && !gallery.favorites.length">
<p>موردی وجود ندارد!</p>
</div>
</div>
</div>
<div class="paginate">
<div class="row">
<div class="col-12">
<el-pagination
layout="next, pager, prev"
v-if="gallery && gallery.all && gallery.all.totalPages > 1"
class="el-pagination"
@current-change="pageNumber"
:current-page="Number($route.query.page)"
:page-count="Number(gallery.all.totalPages)"
>
</el-pagination>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import moment from "moment-jalaali"
export default {
data() {
return {
gallery: null
}
},
computed: {
currentPortal() {
return this.$route.params.portal
},
pageQuery() {
return this.$route.query.page
},
},
watch: {
pageQuery(newVal, oldVal) {
this.$nuxt.refresh()
},
},
methods: {
jDate(date) {
return moment(date).locale('fa').format('LL')
},
pageNumber(val) {
this.$router.push({
name: 'portal-gallery',
params: {portal: this.currentPortal},
query: {type: 'image', page: val}
})
$(window).scrollTop(0)
},
},
async asyncData({params, query, error, $axios}) {
try {
const portalQuery = params.portal
const data = await $axios.get(`/api/public/getAllGallery?portal=${portalQuery}&type=${query.type}&page=${query.page}`)
return {
gallery: data.data
}
} catch (e) {
error({status: 404})
}
}
}
</script>
+148
View File
@@ -0,0 +1,148 @@
<template>
<section class="graphic-details">
<div class="container">
<div class="row">
<div class="view-date">
<p class="date">{{ jalali(info.customDate || info.created_at) }}</p>
<p class="date">{{ jDate(info.customDate || info.created_at) }}</p>
</div>
<div v-if="info.summaryTitle" class="col-12 col-md-6">
<h2 class="summry-title mt-3">
{{ info.summaryTitle }}
</h2>
</div>
<div class="col-12">
<h1 class="title">
{{ info.title }}
</h1>
</div>
<div v-if="info.leadTitle" class="col-12">
<p class="summry-title mb-4">
{{ info.leadTitle }}
</p>
</div>
<div class="row mb-4">
<div class="col-12 img-graphic">
<img style="width : 100%" :src="info.graphic" alt="">
</div>
</div>
</div>
</div>
<div class="s2" v-if="related.length">
<h3>مطالب مرتبط</h3>
<div id="slides">
<div class="slide" v-for="item in related" :key="item._id">
<div class="view-txt">
<div>
<p class="h3">{{ item.title }}</p>
<p>{{ item.summaryTitle }}</p>
<div class="date">
<span>{{ jalali(item.customDate || item.created_at) }}</span>
<span>توسط {{ item._creator.firstName + ' ' + item._creator.lastName }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</template>
<script>
import moment from 'moment-jalaali'
export default {
data() {
return {
info: null,
galleryShown: false,
initialIndex: 0,
related: []
}
},
mounted() {
$(document).ready(() => {
new SimpleLightbox('.graphic-details .img-graphic a')
$("#slides").slick({
dots: true,
slidesToShow: this.related.length === 1 ? 1 : 2,
rtl: true,
responsive: [
{
breakpoint: 960,
settings: {
slidesToShow: 2,
slidesToScroll: 1,
infinite: true,
dots: true
}
},
{
breakpoint: 720,
settings: {
slidesToShow: 2,
slidesToScroll: 1
}
},
{
breakpoint: 540,
settings: {
slidesToShow: 1,
slidesToScroll: 1
}
}
]
})
})
},
methods: {
jalali(date) {
return moment(date).locale('fa').fromNow()
},
jDate(date) {
return moment(date).locale('fa').format('LL')
}
},
head() {
return {
title: 'جزئیات گرافیک',
meta: [
{
hid: 'description',
name: 'description',
content: this.info.summaryTitle
},
{
hid: 'keywords',
name: 'keywords',
content: this.info.keywords
}
]
}
},
async asyncData({params, error, $axios}) {
try {
let data = await $axios.get(`/api/public/getGallery/${encodeURIComponent(params.graphic)}`)
let related = await $axios.get(`/api/public/getRelatedGallery`, {
params: {
type: 'graphic',
title: params.graphic
}
})
return {
info: data.data,
related: related.data
}
} catch (err) {
error({status: 404, message: 'دریافت اطلاعات با مشکل مواجه شده است!'})
}
}
}
</script>
+132
View File
@@ -0,0 +1,132 @@
<template>
<div class="graphic-page">
<div class="container">
<div class="row">
<div class="col-12 col-md-9">
<h3 class="graphic-title">گرافیگ</h3>
<div class="">
<div class="row">
<div class="col-12 mb-5 sectionStyle" v-if="graphic.all.docs.length">
<div class="graphic-item1">
<nuxt-link :to="{name: 'portal-graphics-graphic', params: {portal: currentPortal, graphic: graphic.all.docs[0]._id}}" class="graphic-img-box1">
<img :src="graphic.all.docs[0].thumbCover" alt="" class="graphic-img1">
<div class="graphic-detail-item1">
<h3 class="graphic-detail-title1">{{ graphic.all.docs[0].title }}</h3>
<p class="graphic-detail-date1" id="graphic-detail-date1">{{ jDate(graphic.all.docs[0].customDate || graphic.all.docs[0].created_at) }}</p>
</div>
</nuxt-link>
</div>
</div>
<div class="col-12">
<div class="not-found" v-if="!graphic.all.docs.length">
<p>موردی وجود ندارد!</p>
</div>
</div>
<div class="col-12 col-sm-6 col-md-3 mb-3 sectionStyle" v-for="(item, index) in graphic.all.docs" :key="item.id" v-if="index > 0 && graphic.all.docs.length">
<div class="graphic-item">
<nuxt-link :to="{name: 'portal-graphics-graphic', params: {portal: currentPortal, graphic: item._id}}" class="graphic-img-box">
<img :src="item.thumbCover" alt="" class="graphic-img">
</nuxt-link>
<div class="graphic-detail-item">
<h3 class="graphic-detail-title">{{ item.title }}</h3>
<p class="graphic-detail-date" id="graphic-detail-date">{{ jDate(item.customDate || item.created_at) }}</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-12 col-md-3">
<h3 class="graphic-side">برگزیده ها</h3>
<div class="sectionStyle" v-if="graphic.favorites.length">
<div class="row">
<div class="col-12 col-sm-6 col-md-12 mb-3" v-for="(item, index) in graphic.favorites" :key="item.id" v-if="index < 5">
<div class="graphic-item ">
<nuxt-link :to="{name: 'portal-graphics-graphic', params: {portal: currentPortal, graphic: item._id}}" class="graphic-img-box">
<img :src="item.thumbCover" alt="" class="graphic-img">
</nuxt-link>
<div class="graphic-detail-item">
<h3 class="graphic-detail-title">{{ item.title }}</h3>
<p class="graphic-detail-date" id="graphic-detail-date2">{{ jDate(item.customDate || item.created_at) }}</p>
</div>
</div>
</div>
</div>
</div>
<div class="not-found" v-if="!graphic.favorites.length">
<p>موردی وجود ندارد!</p>
</div>
</div>
</div>
<div class="paginate">
<div class="row">
<div class="col-12">
<el-pagination
layout="next, pager, prev"
v-if="graphic.all.totalPages > 1"
class="el-pagination"
@current-change="pageNumber"
:current-page="Number($route.query.page)"
:page-count="Number(graphic.all.totalPages)"
>
</el-pagination>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import moment from "moment-jalaali"
export default {
data() {
return {
graphic: null
}
},
computed: {
currentPortal() {
return this.$route.params.portal
},
pageQuery() {
return this.$route.query.page
},
},
watch: {
pageQuery(newVal, oldVal) {
this.$nuxt.refresh()
},
},
methods: {
jDate(date) {
return moment(date).locale('fa').format('LL')
},
pageNumber(val) {
this.$router.push({
name: 'portal-graphics',
params: {portal: this.currentPortal},
query: {type: 'graphic', page: val}
})
$(window).scrollTop(0)
},
},
async asyncData({params, query, error, $axios}) {
// return error({status: 404})
try {
const portalQuery = params.portal
// const data = await $axios.get(`/api/public/getgraphicCat/${query.category}`, {
const data = await $axios.get(`/api/public/getAllGallery?portal=${portalQuery}&type=${query.type}&page=${query.page}`)
// console.log('data.data', data.data.all)
return {
graphic: data.data
}
} catch (e) {
error({status: 404})
}
}
}
</script>
+591
View File
@@ -0,0 +1,591 @@
<template>
<div class="home--page">
<section class="event" v-if="homeData.occasion.length">
<div class="container">
<div class="row">
<div class="col-12">
<div id="slides-event">
<div v-for="(item,index) in homeData.occasion" :key="item._id" class="slide" :class="index && 'hide'">
<img :src="item.mainCover" :alt="item.title">
</div>
</div>
</div>
</div>
</div>
</section>
<section class="s1">
<div class="container">
<div class="row">
<div class="col-12">
<div v-if="homeData.s1.length" id="slides">
<div v-for="(item,index) in homeData.s1" :key="item._id" class="slide" :class="index && 'hide' ">
<div class="row">
<div class="txt-holder order-1 order-lg-0 col-12 col-lg-4">
<div class="txtBox">
<h2 :title="item.title">{{ item.title }}</h2>
<p :title="item.summaryTitle" class="p2">{{ item.summaryTitle }}</p>
<nuxt-link
v-if="item.isLocal"
:to="{name: 'portal-news-details',params: {portal: currentPortal,details: item.url}}"
class="btn bigBtn btn-primary bbt"
>
<span>ادامه مطلب</span>
</nuxt-link>
<a class="btn bigBtn btn-primary bbt" :href="item.url" target="_blank" v-else>
<span>ادامه مطلب</span>
</a>
</div>
</div>
<div class="img-holder order-0 order-lg-1 col-12 col-lg-8">
<img :src="item.cover" :alt="item.title">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<div class="container">
<div class="row">
<main class="col-12 col-lg-9 main-content">
<section v-if="homeData.s2 && homeData.s2.length" class="s2">
<LineTxt label="اخبار استاندار"/>
<div class="sectionStyle">
<div class="row">
<!-- <div class="col-12 col-md-6">-->
<!-- <div class="big-image-card">-->
<!-- <img :src="homeData.s2[0].thumbCover"-->
<!-- :alt="homeData.s2[0].title">-->
<!-- <h2>{{ homeData.s2[0].title }}</h2>-->
<!-- <p>{{ homeData.s2[0].summaryTitle }}</p>-->
<!-- <nuxt-link class="btn btn-primary mt-2 mb-4"-->
<!-- :to="{name: 'portal-news-details', params: {portal: currentPortal,-->
<!-- details: homeData.s2[0].title}}">-->
<!-- <span class="txtBtn">ادامه مطلب</span>-->
<!-- </nuxt-link>-->
<!-- </div>-->
<!-- </div>-->
<div class="col-12">
<div class="row">
<NewsBox v-for="item in homeData.s2" :key="item._id" :item="item"/>
</div>
<div class="row mt-3">
<div class="col-12 archive">
<nuxt-link
:to="{name: 'portal-category-details',params: {portal: currentPortal,details: homeData.s2[0].catId.title},query: {type: 'news', page: 1, id: homeData.s2[0].catId._id}}"
class="btn bigBtn btn-primary"
>
<span>آرشیو</span>
</nuxt-link>
</div>
</div>
</div>
</div>
</div>
</section>
<section v-if="homeData.s3.length" class="s3">
<LineTxt label="پرونده خبری"/>
<div class="sectionStyle">
<div class="row">
<nuxt-link
class="title-box"
v-for="(item , index) in homeData.s3"
:key="item._id"
:to="{name: 'portal-newsfile-details',params: {portal:currentPortal,details: item.title},query: {page: 1}}"
v-slot="{href,navigate}"
custom
>
<div @click="navigate" class="col-12 col-md-6 col-lg-3 newsFile">
<img :src="item.thumbCover" :alt="item.title">
<div class="txtBox" :class="index === 0 && 'first'">
<!-- <span>{{ index + 1 }}</span>-->
<a :href="href">
<h2>{{ item.title }}</h2>
</a>
</div>
</div>
</nuxt-link>
</div>
<div class="row mt-3">
<div class="col-12 archive">
<nuxt-link
:to="{name: 'portal-category-details',params: {portal: currentPortal,details: homeData.s3[0].catId.title},query: {type: 'newsFile', page: 1, id: homeData.s3[0].catId._id}}"
class="btn bigBtn btn-primary"
>
<span>آرشیو</span>
</nuxt-link>
</div>
</div>
</div>
</section>
<section v-if="homeData.s4 && homeData.s4.news.length" class="s4">
<LineTxt :label="homeData.s4.nameTag"/>
<div class="sectionStyle">
<div class="row">
<!-- <div class="col-12 col-md-6">-->
<!-- <div class="big-image-card">-->
<!-- <img :src="homeData.s4.news[0].cover" :alt="homeData.s4.news[0].title">-->
<!-- <h2>{{ homeData.s4.news[0].title }}</h2>-->
<!-- <p class="mt-2">-->
<!-- {{ homeData.s4.news[0].summaryTitle }}-->
<!-- </p>-->
<!-- <nuxt-link class="btn btn-primary mt-2 mb-4"-->
<!-- :to="{name: 'portal-news-details', params: {portal: currentPortal,-->
<!-- details: homeData.s4.news[0].title}}">-->
<!-- <span class="txtBtn">ادامه مطلب</span>-->
<!-- </nuxt-link>-->
<!-- </div>-->
<!-- </div>-->
<div class="col-12">
<div class="row">
<NewsBox v-for="item in homeData.s4.news" :key="item._id" :item="item"/>
</div>
</div>
</div>
<div class="row mt-3">
<div class="col-12 archive">
<nuxt-link
:to="{name: 'portal-archive',params: {portal: currentPortal},query: {flag: 'category' , catId : homeData.s4.news[0].rootParent, page: 1}}"
class="btn bigBtn btn-primary"
>
<span>آرشیو</span>
</nuxt-link>
</div>
</div>
</div>
</section>
<section v-if="homeData.s5.length && homeData.s5[0].news.length" class="s5">
<div class="pt-2">
<div class="odd-line">
<!-- <div class="line"></div>-->
<div class="button-holder mb-2">
<div class="line d-none d-md-inline-block"></div>
<div class="row">
<div class="col-12">
<div class="button-holder2" v-for="(item, index) in homeData.s5" :key="item._id">
<button class="btn btn-primary bigBtn" :class="sectionThreeTagIndex === index && 'btn-active'"
@click="sectionThreeTagIndex = index">
<span class="btnTxt">{{ item.nameTag }}</span>
</button>
</div>
</div>
</div>
</div>
</div>
<div class="sectionStyle">
<div class="row" v-if="sectionThreeData.length">
<div class="col-12 mt-4">
<div class="row">
<div class="row">
<div v-for="item in sectionThreeData" :key="item._id" class="col-12 col-md-6">
<nuxt-link :to="{name: 'portal-news-details', params: {portal: currentPortal, details: item._id}}" :title="item.title">
<div class="txt-holder">
<i class="fas fa-globe-asia"></i>
<h2>{{ item.title }}</h2>
</div>
</nuxt-link>
</div>
</div>
</div>
</div>
<div class="col-12 mt-4 d-flex justify-content-center">
<nuxt-link
:to="{name: 'portal-archive',params: {portal: currentPortal},query: {flag: 'category' , catId : sectionThreeData[0].rootParent, page: 1}}"
class="btn bigBtn btn-primary"
>
<span>آرشیو</span>
</nuxt-link>
</div>
</div>
<div class="not-found" v-else>
<p>موردی وجود ندارد!</p>
</div>
</div>
</div>
</section>
<section v-if="homeData.s6 && homeData.s6.length" class="s6">
<LineTxt label="پربیننده ترین ها"/>
<div class="sectionStyle">
<div class="row">
<!-- <div class="col-12 col-md-6">-->
<!-- <div class="big-image-card">-->
<!-- <img :src="homeData.s6[0].thumbCover" :alt="homeData.s6[0].title">-->
<!-- <h2>{{ homeData.s6[0].title }}</h2>-->
<!-- <p class="mt-2">-->
<!-- {{ homeData.s6[0].summaryTitle }}-->
<!-- </p>-->
<!-- <nuxt-link class="btn btn-primary mt-2 mb-4"-->
<!-- :to="{name: 'portal-news-details', params: {portal: currentPortal,-->
<!-- details: homeData.s6[0].title}}">-->
<!-- <span>ادامه مطلب</span>-->
<!-- </nuxt-link>-->
<!-- </div>-->
<!-- </div>-->
<div class="col-12">
<div class="row">
<NewsBox v-for="item in homeData.s6" :key="item._id" :item="item"/>
</div>
</div>
</div>
</div>
</section>
</main>
<aside class="col-lg-3 d-none d-lg-block side-bar">
<div class="boss" v-for="item in homeData.s1Side" :key="item._id">
<nuxt-link :to="{name: 'portal-info-page', params:{ portal: currentPortal, page: 'manager'}}" v-slot="{href,navigate}" custom>
<div class="sectionStyle">
<a :href="href" class="txtLink">
<img @click="navigate" :src="item.thumb" :alt="item.title">
</a>
<div class="links">
<a :href="href" @click="navigate" class="txtLink title">{{ item.title }}</a>
<h2>
<a :href="href" @click="navigate" class="txtLink">استاندار مرکزی</a>
</h2>
<a :href="`mailto: ${item.email}`" target="_blank" class="mailLink">
<span>ایمیل: </span>
<span>{{ item.email }}</span>
</a>
<nuxt-link :to="{name: 'portal-services-meeting', params: {portal: currentPortal}}" class="btn btn-primary">
<span class="txtBtn">راه ارتباطی</span>
</nuxt-link>
</div>
</div>
</nuxt-link>
</div>
<div v-if="homeData.s5Side.length" class="spec-news mt-3">
<SideBarLineTxt label="مطالب ویژه"/>
<div class="sectionStyle">
<div id="slides-spec">
<nuxt-link
v-for="item in homeData.s5Side"
:key="item._id"
:to="{name: 'portal-news-details', params: {portal: currentPortal,details: item._id}}"
v-slot="{href,navigate}"
custom
>
<div @click="navigate" class="slide pointer" :title="item.title">
<img :src="item.cover" :alt="item.title">
<a :href="href">{{ item.title }}</a>
</div>
</nuxt-link>
</div>
</div>
</div>
<div class="multimedia mt-3" v-if="homeData.s2Side.length || homeData.s3Side.length || homeData.s4Side.length">
<SideBarLineTxt label="چندرسانه ای"/>
<div class="sectionStyle">
<div class="media" v-if="homeData.s2Side.length" id="sideImageSlider">
<nuxt-link
v-for="item in homeData.s2Side"
:key="item._id"
:to="{name: 'portal-gallery-media', params: {portal: currentPortal,media: item._id}}"
>
<div class="image slide pointer" :title="item.title">
<img :src="item.thumbCover" :alt="item.title">
<div class="txtBox">
<span class="tag">عکس</span>
<a>{{ item.title }}</a>
<div class="btns">
<!-- <a :href="href" class="btn btn-primary">-->
<!-- <span class="txtBtn">مشاهده</span>-->
<!-- </a>-->
<nuxt-link
:to="{name: 'portal-category-details',params: {portal: currentPortal,details: item.catId.title},query: {id: item.catId._id,type: 'gallery',galleryType: 'image',page: 1}}"
class="btn btn-primary">
<span class="txtBtn">آرشیو</span>
</nuxt-link>
</div>
</div>
</div>
</nuxt-link>
</div>
<!-- <div v-if="homeData.s3Side.length" class="videos">-->
<!-- <img class="img-item" :src="homeData.s3Side[0].thumbCover" :alt="homeData.s3Side[0].title">-->
<!-- <span class="tag">فیلم</span>-->
<!-- <nuxt-link :to="{name: 'portal-videos-video', params: {portal: currentPortal,video: homeData.s3Side[0].title}}">-->
<!-- <p class="title-gallery">{{ homeData.s3Side[0].title }}</p>-->
<!-- </nuxt-link>-->
<!-- </div>-->
<div class="media" :class="homeData.s2Side.length && media_video" v-if="homeData.s3Side.length" id="sideVideoSlider">
<nuxt-link
v-for="item in homeData.s3Side"
:key="item._id"
:to="{name: 'portal-videos-video', params: {portal: currentPortal,video: item._id}}"
>
<div class="video slide pointer" :title="item.title">
<img :src="item.thumbCover" :alt="item.title">
<div class="txtBox">
<span class="tag">فیلم</span>
<a>{{ item.title }}</a>
<div class="btns">
<!-- <a :href="href" class="btn btn-primary">-->
<!-- <span class="txtBtn">مشاهده</span>-->
<!-- </a>-->
<nuxt-link
:to="{name: 'portal-category-details',params: {portal: currentPortal,details: item.catId.title},query: {id: item.catId._id,type: 'gallery',galleryType: 'video',page: 1}}"
class="btn btn-primary">
<span class="txtBtn">آرشیو</span>
</nuxt-link>
</div>
</div>
</div>
</nuxt-link>
</div>
<!-- <div v-if="homeData.s4Side.length" class="graphics">-->
<!-- <img class="img-item" :src="homeData.s4Side[0].thumbCover" :alt="homeData.s4Side[0].title">-->
<!-- <span class="tag">گرافیک</span>-->
<!-- <nuxt-link :to="{name: 'portal-graphics-graphic', params: {portal: currentPortal,graphic: homeData.s4Side[0].title}}">-->
<!-- <p class="title-gallery">{{ homeData.s4Side[0].title }}</p>-->
<!-- </nuxt-link>-->
<!-- </div>-->
<div class="media" :class="homeData.s3Side.length || homeData.s2Side.length && media_graphic" v-if="homeData.s4Side.length" id="sideGraphicSlider">
<nuxt-link
v-for="item in homeData.s4Side"
:key="item._id"
:to="{name: 'portal-graphics-graphic', params: {portal: currentPortal,graphic: item._id}}"
>
<div class="graphic slide pointer" :title="item.title">
<img :src="item.thumbCover" :alt="item.title">
<div class="txtBox">
<span class="tag">گرافیک</span>
<a>{{ item.title }}</a>
<div class="btns">
<!-- <a :href="href" class="btn btn-primary">-->
<!-- <span class="txtBtn">مشاهده</span>-->
<!-- </a>-->
<nuxt-link
:to="{name: 'portal-category-details',params: {portal: currentPortal,details: item.catId.title},query: {id: item.catId._id,type: 'gallery',galleryType: 'graphic',page: 1}}"
class="btn btn-primary">
<span class="txtBtn">آرشیو</span>
</nuxt-link>
</div>
</div>
</div>
</nuxt-link>
</div>
</div>
</div>
<div v-if="homeData.notificationsSide.length" class="notifications links mt-3">
<SideBarLineTxt label="اطلاعیه ها"/>
<div class="sectionStyle">
<ul>
<li class="mb-2" v-for="item in homeData.notificationsSide" :key="item._id">
<nuxt-link :to="{name: 'portal-news-details', params: {portal: currentPortal,details: item._id}}" :title="item.title">
<i class="fal fa-megaphone"></i>
<span>{{ item.title }}</span>
</nuxt-link>
</li>
</ul>
</div>
</div>
<div v-if="homeData.s6Side.length" class="latest_news mt-3">
<SideBarLineTxt label="آخرین اخبار"/>
<div class="sectionStyle">
<ul>
<li v-for="item in homeData.s6Side" :key="item._id">
<nuxt-link
:to="{name: 'portal-news-details', params: {portal: currentPortal,details: item._id}}"
:title="item.title"
>
<i class="fas fa-circle"></i>
<span>{{ item.title }}</span>
</nuxt-link>
</li>
</ul>
</div>
</div>
<div v-if="homeData.s7Side.length" class="links mt-3">
<SideBarLineTxt label="پیوند ها"/>
<div class="sectionStyle">
<ul>
<li class="mb-2" v-for="link in homeData.s7Side" :key="link._id">
<a :href="link.url" :title="link.title" target="_blank">
<i class="fal fa-link"></i>
<span>{{ link.title }}</span>
</a>
</li>
</ul>
</div>
</div>
</aside>
</div>
</div>
</div>
</template>
<script>
if (process.client) require("slick-carousel")
import moment from 'moment-jalaali'
export default {
name: "index",
data() {
return {
sectionThreeTagIndex: 0,
homeData: null,
dialogTimeVisible: false
}
},
computed: {
currentPortal() {
return this.$route.params.portal
},
sectionThreeTag() {
return this.homeData.s5[this.sectionThreeTagIndex]?.nameTag
},
sectionThreeData() {
return this.homeData.s5.find(item => item.nameTag === this.sectionThreeTag)?.news
},
counterDown() {
return this.$store.state.front.counterDown.expireDate.split('T')
}
},
methods: {
jDate(data) {
return moment(data).locale('fa').fromNow()
},
},
mounted() {
$(document).ready(() => {
//////////////////// slides - section1
$("#slides").on('init', function () {
$('#slides .slide').removeClass('hide')
})
$("#slides").slick({
dots: true,
slidesToShow: 1,
rtl: true,
autoplay: true,
autoplaySpeed: 3000,
speed: 1000,
arrows: false,
infinite: false
})
//////////////////// sidebar - images
$("#sideImageSlider").on('init', function () {
$('#sideImageSlider .slide').removeClass('hide')
})
$("#sideImageSlider").slick({
dots: true,
slidesToShow: 1,
rtl: true,
autoplay: true,
autoplaySpeed: 5000,
speed: 1000,
arrows: false,
infinite: false,
pauseOnHover: true
})
//////////////////// sidebar - videos
$("#sideVideoSlider").on('init', function () {
$('#sideVideoSlider .slide').removeClass('hide')
})
$("#sideVideoSlider").slick({
dots: true,
slidesToShow: 1,
rtl: true,
autoplay: true,
autoplaySpeed: 3000,
speed: 1000,
arrows: false,
infinite: false,
pauseOnHover: true
})
//////////////////// sidebar - graphics
$("#sideGraphicSlider").on('init', function () {
$('#sideGraphicSlider .slide').removeClass('hide')
})
$("#sideGraphicSlider").slick({
dots: true,
slidesToShow: 1,
rtl: true,
autoplay: true,
autoplaySpeed: 4000,
speed: 1000,
arrows: false,
infinite: false,
pauseOnHover: true
})
//////////////////// slides-spec
$("#slides-spec").slick({
dots: true,
slidesToShow: 1,
rtl: true,
autoplay: true,
autoplaySpeed: 3000,
speed: 1000,
arrows: false,
infinite: false,
pauseOnHover: true
})
//////////////////// slides-event
$("#slides-event").on('init', function () {
$('#slides-event .slide').removeClass('hide')
})
$("#slides-event").slick({
dots: false,
slidesToShow: 1,
rtl: true,
autoplay: true,
autoplaySpeed: 3500,
speed: 1000,
arrows: false,
pauseOnHover: true
})
})
},
async asyncData({$axios, store, error, params}) {
const portalQuery = params.portal
try {
const homeData = await $axios.get(`/api/public/home?portal=${portalQuery}`)
store.commit('front/setHomePageData', homeData.data)
return {
homeData: homeData.data
}
} catch (e) {
error({status: 500, message: "مشکلی پیش آمده است!"})
}
}
}
</script>
+33
View File
@@ -0,0 +1,33 @@
<template>
<div class="info--page">
<div class="container">
<h2 class="title">{{ listData.title }}</h2>
<img :src="listData.cover" :alt="listData.title" v-if="$route.params.page === 'manager'">
<div class="ck-content" v-html="listData.pageContent"></div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
listData: []
}
},
async asyncData({$axios, error, params}) {
try {
const data = await $axios.get(`/api/public/viewContent/${params.page}`)
return {
listData: data.data
}
} catch (e) {
error({status: 404})
}
}
}
</script>
+46
View File
@@ -0,0 +1,46 @@
<template>
<div class="links-page">
<div class="container">
<div class="row">
<div class="col-12">
<LineTxt label="پیوند ها"/>
</div>
<div class="col-12 col-md-6 links-view" v-for="item in links" :key="item._id">
<a :href="item.url" target="_blank" class="links-item">
<i class="far fa-check-square"></i>
<span>{{ item.title }}</span>
</a>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
links: null
}
},
computed: {
currentPortal() {
return this.$route.params.portal
},
},
async asyncData({$axios, error, params}) {
const portalQuery = params.portal
try {
const links = await $axios.get(`/api/public/getLinks?portal=${portalQuery}`)
return {
links: links.data
}
} catch (e) {
error({status: 500, message: "مشکلی پیش آمده است!"})
}
}
}
</script>
+424
View File
@@ -0,0 +1,424 @@
<template>
<div class="news_details">
<section class="s1">
<div class="container">
<div class="row">
<main class="col-12 col-lg-9 ol">
<div class="menu-right-details">
<p>{{ fullData.news.summaryTitle }}</p>
<h1 class="mb-2">{{ fullData.news.title }}</h1>
<div class="s1-view-time">
<!-- <nuxt-link :to="{name: 'portal-category-details',params: {portal: currentPortal ,-->
<!-- details: fullData.news.catId.title},query: {type: 'news',page: 1, id: fullData.news._id}}" class="s1-cat">{{ fullData.news.catId.title }}-->
<!-- </nuxt-link>-->
<div>
<p class="userName">توسط {{ fullData.news._creator.firstName + ' ' + fullData.news._creator.lastName }} </p>
<p class="time">{{ jData(fullData.news.customDate) }}</p>
</div>
</div>
<div class="d-flex justify-content-between">
<div class="sharableLinks">
<p>به اشتراک بگذارید:</p>
<ul>
<li>
<el-popover
placement="top-end"
title=""
trigger="manual"
width="100"
content="آدرس کپی شد"
:value="popup"
>
<i @click="copyToClipboard(pageURL)" slot="reference" class="fas fa-share-alt" title="آدرس را کپی کنید"></i>
</el-popover>
</li>
<li>
<ShareNetwork
network="email"
:url="pageURL"
:title="fullData.news.title"
:description="fullData.news.shortSummaryTitle"
>
<i class="fas fa-envelope" title="ایمیل"></i>
</ShareNetwork>
</li>
<li>
<ShareNetwork
network="facebook"
:url="pageURL"
:title="fullData.news.title"
:description="fullData.news.shortSummaryTitle"
:hashtags="fullData.news.keywords"
>
<i class="fab fa-facebook-f" title="فیسبوک"></i>
</ShareNetwork>
</li>
<li>
<ShareNetwork
network="telegram"
:url="pageURL"
:title="fullData.news.title"
:description="fullData.news.shortSummaryTitle"
>
<i class="fab fa-telegram-plane" title="تلگرام"></i>
</ShareNetwork>
</li>
<li>
<ShareNetwork
network="WhatsApp"
:url="pageURL"
:title="fullData.news.title"
:description="fullData.news.shortSummaryTitle"
>
<i class="fab fa-whatsapp" title="واتس اپ"></i>
</ShareNetwork>
</li>
<li>
<ShareNetwork
network="LinkedIn"
:url="pageURL"
:title="fullData.news.title"
:description="fullData.news.shortSummaryTitle"
>
<i class="fab fa-linkedin-in" title="لینکد این"></i>
</ShareNetwork>
</li>
</ul>
</div>
<!-- <div class="d-flex">-->
<!-- <span><i class="far fa-eye"></i></span>-->
<!-- <span style="margin-right: 8px; font-family: 'sansNum', sans-serif">{{fullData.news.userViews}}</span>-->
<!-- </div>-->
</div>
<img style="width: 100%" :src="fullData.news.cover" alt="">
<p class="mt-2 mb-3 leadTitle">{{ fullData.news.leadTitle }}</p>
<div class="sk-editor-field ck-content" v-html="fullData.news.pageContent"></div>
</div>
<div v-if="fullData.news.attachments.length">
<el-divider></el-divider>
<div class="row">
<div class="col-12 view-page-terms" v-for="item in fullData.news.attachments" :key="item._id">
<div class="view-item-terms">
<div class="view-title-terms">
<i class="far fa-folder-open"></i>
<h3 :title="item.title">{{ item.title }}</h3>
</div>
<div>
<a class="btn btn-primary" :href="item.file" target="_blank">مطالعه کنید</a>
<a class="btn btn-primary" :href="item.file" target="_blank" download>دانلود</a>
</div>
</div>
</div>
</div>
<el-divider></el-divider>
</div>
<div class="menu-right-comment" v-if="fullData.news.allowComment">
<LineTxt label="افزودن نظر"/>
<form @submit.prevent="post">
<div class="row">
<div class="col-12 col-md-6 formRow" :class="validation.name ? 'err' : null">
<input v-model="message.name" class="input" name="name" type="text"
placeholder="نام و نام خانوادگی خود را وارد کنید"/>
<p v-if="validation.name">{{ validation.name.msg }}</p>
</div>
<div class="col-12 col-md-6 formRow" :class="validation.email ? 'err' : null">
<input v-model="message.email" class="input" name="email" type="text" placeholder="ایمیل خود را وارد کنید"/>
<p v-if="validation.email">{{ validation.email.msg }}</p>
</div>
</div>
<div class="formRow" :class="validation.description ? 'err' : null">
<textarea v-model="message.description" name="description" class="input" rows="4" placeholder="توضیحات خود را وارد کنید"></textarea>
<p v-if="validation.description">{{ validation.description.msg }}</p>
</div>
<div class="row view-captcha">
<div class="col-12 col-md-4 formRow" :class="validation.captcha ? 'err' : null">
<input v-model="message.captcha" class="input" name="captcha" type="text" placeholder="متن داخل عکس را وارد کنید"/>
<p class="err-captcha" v-if="validation.captcha">{{ validation.captcha.msg }}</p>
</div>
<div class="col-12 col-md-4 new-captcha">
<div class="captcha" v-html="captcha"></div>
<button @click="reloadCaptcha" type="button" class="btn btn-primary">
<i class="fas fa-sync-alt"></i>
</button>
</div>
<div class="col-12 col-md-4 btnSub">
<button class="btn-link" type="submit">ارسال</button>
<!-- <nuxt-link >SUBMIT NOW</nuxt-link> -->
</div>
</div>
</form>
<div class="view-comment" v-if="fullData.comments.length">
<LineTxt label="نظرات"/>
<div class="container">
<div class="row view-comment-item" v-for="item in fullData.comments" :key="item._id">
<div class="col-6 title">
<h4>{{ item.name }}</h4>
</div>
<div class="col-6 date" style="text-align: left">
<span>{{ jData3(item.customDate) }}</span>
</div>
<div class="col-6 desc">
<h3>{{ item.description }}</h3>
</div>
</div>
</div>
</div>
</div>
</main>
<aside class="col-lg-3 d-none d-lg-block">
<div class="newests">
<SideBarLineTxt label="جدیدترین ها"/>
<div class="sectionStyle">
<nuxt-link
v-if="newNews.docs.length"
v-for="item in newNews.docs"
:key="item._id"
:to="{name: 'portal-news-details', params: {portal: currentPortal,details: item._id}}"
v-slot="{href,navigate}"
custom
>
<div class="news-box" :title="item.title" @click="navigate">
<a :href="href">
<h4 class="title">{{ item.title }}</h4>
</a>
<p :title="item.summaryTitle">{{ item.summaryTitle }}</p>
<div class="view-date-menu-left">
<span class="date-jalali">{{ jData2(item.customDate) }}</span>
<span class="date-jalali">{{ jData3(item.customDate) }}</span>
</div>
</div>
</nuxt-link>
</div>
</div>
<div class="betweenNewsPickUp mt-3">
<SideBarLineTxt label="از میان خبر ها"/>
<div class="sectionStyle">
<div v-if="randomNews.length" v-for="item in randomNews" :title="item.title" class="news-with-img">
<nuxt-link :to="{name: 'portal-news-details', params: {portal: currentPortal,details : item._id}}">
<img :src="item.cover" :alt="item.title">
<p class="title">{{ item.title }}</p>
<span class="date-jalali">{{ jData2(item.customDate) }}</span>
<span class="date-jalali">{{ jData3(item.customDate) }}</span>
</nuxt-link>
</div>
</div>
</div>
<div class="mostViewed mt-3">
<SideBarLineTxt label="پر بازدید ترین"/>
<div class="sectionStyle">
<nuxt-link v-if="mostViewed.docs.length" v-for="(item , index) in mostViewed.docs" :key="item._id" class="red-num-txt-box"
:to="{name: 'portal-news-details',params: {portal: currentPortal,details: item._id}}" :title="item.title">
<span class="enum">{{ index + 1 }}</span>
<p>{{ item.title }}</p>
<div class="gray-line"></div>
</nuxt-link>
</div>
</div>
</aside>
</div>
</div>
</section>
<section class="s2">
<div class="container">
<LineTxt label="مطالب مرتبط"/>
<div class="row">
<div class="col-12 col-md-4 mb-5" v-for="item in relatedNews" :key="item._id">
<nuxt-link
:to="{name: 'portal-news-details',params: {portal: currentPortal,details: item._id}}"
v-slot="{navigate,href}"
custom
>
<div class="img-overlay-text" @click="navigate" :title="item.title">
<img :src="item.thumbCover" :alt="item.title">
<div class="txt-holder">
<div class="gray-back">
<a :href="href">{{ item.title }}</a>
</div>
</div>
</div>
</nuxt-link>
</div>
</div>
</div>
</section>
</div>
</template>
<script>
import moment from 'moment-jalaali'
export default {
data() {
return {
fullData: null,
newNews: null,
randomNews: null,
mostViewed: null,
relatedNews: null,
message: {
name: '',
email: '',
description: '',
captcha: '',
modelName: 'news',
modelId: ''
},
validation: {},
popup: false,
captcha: null
}
},
computed: {
currentPortal() {
return this.$route.params.portal
},
pageURL() {
return process.client ? window.location.href : ''
}
},
methods: {
jData(data) {
return moment(data).locale('fa').format('a h:mm - jYYYY/jMM/jDD')
},
jData2(data) {
return moment(data).locale('fa').fromNow()
},
jData3(data) {
return moment(data).locale('fa').format('jYYYY/jMM/jDD')
},
copyToClipboard(str) {
this.popup = true
setTimeout(() => this.popup = false, 3000)
// Create new element
let el = document.createElement('textarea');
// Set value (string to be copied)
el.value = str;
// Set non-editable to avoid focus and move outside of view
el.setAttribute('readonly', '');
el.style = {position: 'absolute', left: '-9999px'};
document.body.appendChild(el);
// Select text inside element
el.select();
// Copy text to clipboard
document.execCommand('copy');
// Remove temporary element
document.body.removeChild(el);
// Show Message
// let popup = document.getElementById("myPopup");
// popup.classList.toggle("show");
},
post() {
this.validation = {}
this.$axios.post('/api/public/addComment', {...this.message, modelId: this.fullData.news._id})
.then(res => {
this.reloadCaptcha()
this.$message({
type: 'success',
message: 'پیام شما با موفقیت ارسال شد'
})
this.message = {
name: '',
email: '',
description: '',
captcha: '',
modelName: 'news',
modelId: ''
}
})
.catch(e => {
this.reloadCaptcha()
if (e.response.status === 422) this.validation = e.response.data.validation
else console.log(e)
})
},
reloadCaptcha() {
this.$axios.get('/api/public/getCaptcha').then(res => {
this.captcha = res.data
})
}
},
head() {
return {
title: 'جزئیات خبر',
meta: [
{
hid: 'description',
name: 'description',
content: this.fullData.news.summaryTitle
},
{
hid: 'keywords',
name: 'keywords',
content: this.fullData.news.keywords
}
]
}
},
async asyncData({$axios, error, params}) {
const portal = params.portal
try {
const request = [
// news details
$axios.get(`/api/public/viewNews/${encodeURIComponent(params.details)}`),
// new news
$axios.get('/api/public/getnews', {
params: {
flag: "new",
portal: portal
}
}),
// random news
$axios.get('/api/public/getnews', {
params: {
flag: "random",
portal: portal
}
}),
// most viewed news
$axios.get("/api/public/getnews", {
params: {
flag: "popular",
portal: portal
}
}),
// related news
$axios.get('/api/public/getRelatedNews', {
params: {
portal: portal,
title: params.details
}
}),
// get captcha
$axios.get('/api/public/getCaptcha')
]
const fetch = await Promise.all(request)
const [res, NewNews, RandomNews, mostViewed, relatedNews, captcha] = fetch
return {
fullData: res.data,
newNews: NewNews.data,
randomNews: RandomNews.data,
mostViewed: mostViewed.data,
relatedNews: relatedNews.data,
captcha: captcha.data
}
} catch (e) {
error({status: 404, message: 'مشکلی پیش آمده است!'})
}
},
}
</script>
+182
View File
@@ -0,0 +1,182 @@
<template>
<section class="news-file-details">
<section class="s1 mb-3">
<div class="container">
<LineTxt :label="newsFile.newsFile.title"/>
<div class="sectionStyle">
<div class="row" v-if="newsFile.news.docs.length">
<div class="col-12 col-md-6">
<img :src="newsFile.news.docs[0].thumbCover" class="img-hold" :alt="newsFile.news.docs[0].title">
</div>
<div class="news_holder col-12 col-md-6">
<!-- <h2 class="s1-title" :title="newsFile.news.docs[0].summaryTitle">{{ newsFile.news.docs[0].summaryTitle }}</h2>-->
<p class="s1-description mb-4 mt-4" :title="newsFile.news.docs[0].title">{{ newsFile.news.docs[0].title }}</p>
<p class="s1-description lid" :title="newsFile.news.docs[0].leadTitle">{{ newsFile.news.docs[0].leadTitle }}</p>
<div class="date">
<p>{{ jDate(newsFile.news.docs[0].customDate) }}</p>
</div>
<nuxt-link
:to="{name: 'portal-news-details',
params: {portal: currentPortal, details: newsFile.news.docs[0]._id}}" class="btn btn-primary">
<span>ادامه مطلب</span>
</nuxt-link>
</div>
</div>
<div class="not-found" v-else>
<p>موردی وجود ندارد!</p>
</div>
</div>
</div>
</section>
<section class="s2" v-if="newsFile.news.docs.length > 1">
<div class="container">
<!-- <LineTxt label="سایر اخبار"/>-->
<div class="sectionStyle">
<div class="row">
<!-- <div class="col-12 col-md-9 mb-3 bigNews">-->
<!-- <div class="row">-->
<!-- <div class="col-12 order-1 col-md-4 order-md-0">-->
<!--&lt;!&ndash; <h2 class="s2-title1" :title="newsFile.news.docs[1].summaryTitle">{{ newsFile.news.docs[1].summaryTitle }}</h2>&ndash;&gt;-->
<!-- <p class="desc" :title="newsFile.news.docs[1].title">{{ newsFile.news.docs[1].title }}</p>-->
<!-- <p class="desc" :title="newsFile.news.docs[1].leadTitle">{{ newsFile.news.docs[1].leadTitle }}</p>-->
<!-- <div class="date">-->
<!-- <p>{{ jDate(newsFile.news.docs[1].customDate) }}</p>-->
<!-- </div>-->
<!-- <nuxt-link-->
<!-- :to="{name: 'portal-news-details',params: {portal: currentPortal, details: newsFile.news.docs[1]._id}}"-->
<!-- class="btn btn-primary">-->
<!-- <span>ادامه مطلب</span>-->
<!-- </nuxt-link>-->
<!-- </div>-->
<!-- <div class="col-12 order-0 col-md-8 order-md-1">-->
<!-- <img :src="newsFile.news.docs[1].thumbCover" :alt="newsFile.news.docs[1].title">-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="col-12 col-md-3 mb-4"-->
<!-- v-for="(item, index) in newsFile.news.docs" v-if="index > 1" :key="item._id">-->
<!-- <img :src="item.thumbCover" :alt="item.title">-->
<!-- <h3 class="mt-4 mb-4 s2-title2">{{ item.title }}</h3>-->
<!-- <div class="view-date">-->
<!-- <span class="date">{{ jDate2(item.customDate) + ' - ' + jDate(item.customDate) }}</span>-->
<!-- <nuxt-link :to="{name: 'portal-news-details',params: {portal: currentPortal, details: item.title}}">-->
<!-- <span class="but">ادامه مطلب<i class="fas fa-chevron-left"></i></span>-->
<!-- </nuxt-link>-->
<!-- </div>-->
<!-- </div>-->
<NewsBox v-for="(item, index) in newsFile.news.docs" v-if="index > 0" :key="item._id" :item="item" :timeIsAgo="false"/>
<!-- ******************************************* old style ******************************************* -->
<!-- <nuxt-link-->
<!-- v-for="(item, index) in newsFile.news.docs" v-if="index > 1"-->
<!-- :key="item._id"-->
<!-- :to="{name: 'portal-news-details', params: {portal: currentPortal,details: item.title}}"-->
<!-- v-slot="{href,navigate}"-->
<!-- custom-->
<!-- >-->
<!-- <div @click="navigate" class="small-pics justifyBetween col-12 col-md-3 mb-4 pointer">-->
<!-- <img :src="item.thumbCover" :alt="item.title">-->
<!-- <h2 class="mt-2">{{ item.title }}</h2>-->
<!-- <div class="row view-time-ago">-->
<!-- <div class="col-12 col-xxl-6">-->
<!-- <p>{{ jDate(item.customDate) }}</p>-->
<!-- </div>-->
<!-- <div class="col-12 col-xxl-6">-->
<!-- <a :href="href" class="btn btn-primary mt-2">-->
<!-- <span class="txtBtn">ادامه مطلب</span>-->
<!-- </a>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </nuxt-link>-->
<!-- ******************************************* old style ******************************************* -->
</div>
</div>
</div>
</section>
<div class="paginate">
<div class="row">
<div class="col-12">
<el-pagination
layout="prev, pager, next"
v-if="paginate"
class="el-pagination"
@current-change="newsPageNumber"
:current-page="Number($route.query.page)"
:page-count="Number(newsFile.news.totalPages)"
>
</el-pagination>
</div>
</div>
</div>
</section>
</template>
<script>
import moment from "moment-jalaali"
export default {
data() {
return {
newsFile: null
}
},
computed: {
currentPortal() {
return this.$route.params.portal
},
paginate() {
return this.newsFile.news.totalPages > 1
},
pageQuery() {
return this.$route.query.page
},
},
watch: {
pageQuery(newVal, oldVal) {
this.$nuxt.refresh()
},
},
methods: {
jDate(data) {
return moment(data).locale('fa').format('LL')
},
jDate2(data) {
return moment(data).locale('fa').fromNow()
},
newsPageNumber(val) {
this.$router.push({
name: 'portal-newsfile-details',
params: {portal: this.currentPortal, details: this.$route.params.details},
query: {page: val}
})
$(window).scrollTop(0)
},
},
head() {
return {
title: 'پرونده خبری'
}
},
async asyncData({$axios, params, error, query}) {
try {
const newsFile = await $axios.get(`/api/public/getnewsfile/${encodeURIComponent(params.details)}?page=${query.page}`)
return {
newsFile: newsFile.data
}
} catch (e) {
error({status: 404, message: 'در دریافت اطلاعات مشکلی پیش آمده است!'})
}
}
}
</script>
File diff suppressed because it is too large Load Diff
+266
View File
@@ -0,0 +1,266 @@
<template>
<div class="search-result">
<section class="results-for">
<div class="container">
<div class="row">
<div class="col-12">
<h2>
<span>نتایج جستجو برای: </span>
<b>{{ $route.query.sq }}</b>
</h2>
</div>
</div>
</div>
</section>
<section class="news">
<div class="container">
<div class="row title">
<div class="col-12">
<h2 @click="toggleResults('news')">
<i class="fas fa-chevron-circle-left" :class="newsOpen && 'open'"></i>
<span>نتایج جستجو در اخبار:</span>
<b>{{ result.news.length }}</b>
</h2>
<p v-if="!result.news.length">هیچ نتیجه ای پیدا نشد.</p>
</div>
</div>
<!----------------------- Short result ------------------------->
<div class="row align-items-stretch">
<div class="col-12 col-md-6 col-lg-3 mb-5" v-for="(item,index) in result.news" :key="item._id" :title="item.title" v-if="index < 4">
<div class="news-item">
<img :src="item.thumbCover" :alt="item.title">
<h2>{{ item.title }}</h2>
<p>{{ item.summaryTitle }}</p>
<nuxt-link class="btn btn-primary" :to="{name: 'portal-news-details',params: {portal: item.modelType,details: item._id}}">ادامه مطلب</nuxt-link>
</div>
</div>
</div>
<!----------------------- Short result ------------------------->
<!----------------------- Full result ------------------------->
<div class="row align-items-stretch results">
<div class="col-12 col-md-6 col-lg-3 mb-5" v-for="(item,index) in result.news" :key="item._id" :title="item.title" v-if="index >= 4">
<div class="news-item">
<img :src="item.thumbCover" :alt="item.title">
<h2>{{ item.title }}</h2>
<p>{{ item.summaryTitle }}</p>
<nuxt-link class="btn btn-primary" :to="{name: 'portal-news-details',params: {portal: item.modelType,details: item._id}}">ادامه مطلب</nuxt-link>
</div>
</div>
</div>
<!----------------------- Full result ------------------------->
<div class="row seeMore" v-if="result.news.length > 4">
<div class="col-12">
<button @click="toggleResults('news')">
<span v-if="!newsOpen">نتایج بیشتر</span>
<span v-else>نتایج کمتر</span>
<i class="fas fa-chevron-double-down" :class="newsOpen && 'open'"></i>
</button>
</div>
<!-- <div class="col-12">-->
<!-- <div class="line"></div>-->
<!-- </div>-->
</div>
</div>
</section>
<section class="pages">
<div class="container">
<div class="row title">
<div class="col-12">
<h2 @click="toggleResults('pages')">
<i class="fas fa-chevron-circle-left" :class="pagesOpen && 'open'"></i>
<span>نتایج جستجو در صفحات:</span>
<b>{{ result.pages.length }}</b>
</h2>
<p v-if="!result.pages.length">هیچ نتیجه ای پیدا نشد.</p>
</div>
</div>
<!----------------------- Short result ------------------------->
<div class="row align-items-stretch">
<div class="col-12 col-md-4 col-lg-3 mb-3" v-for="(item,index) in result.pages" :key="item._id" :title="item.title" v-if="index < 4">
<div class="pages-item">
<nuxt-link v-if="!item.url" :to="{name: 'portal-category-details',params: {portal: item.modelType,details: item.title}, query: categoryURLQuery(item)}">{{ item.title }}</nuxt-link>
<a v-else :href="item.url">ادامه مطلب</a>
</div>
</div>
</div>
<!----------------------- Short result ------------------------->
<!----------------------- full result ------------------------->
<div class="row align-items-stretch results">
<div class="col-12 col-md-4 col-lg-3 mb-3" v-for="(item,index) in result.pages" :key="item._id" :title="item.title" v-if="index >= 4">
<div class="pages-item">
<nuxt-link v-if="!item.url" :to="{name: 'portal-category-details',params: {portal: item.modelType,details: item.title}, query: categoryURLQuery(item)}">{{ item.title }}</nuxt-link>
<a v-else :href="item.url">ادامه مطلب</a>
</div>
</div>
</div>
<!----------------------- full result ------------------------->
<div class="row seeMore" v-if="result.pages.length > 4">
<div class="col-12">
<button @click="toggleResults('pages')">
<span v-if="!pagesOpen">نتایج بیشتر</span>
<span v-else>نتایج کمتر</span>
<i class="fas fa-chevron-double-down" :class="pagesOpen && 'open'"></i>
</button>
</div>
<!-- <div class="col-12 mt-4">-->
<!-- <div class="line"></div>-->
<!-- </div>-->
</div>
</div>
</section>
<section class="media">
<div class="container">
<div class="row title">
<div class="col-12">
<h2 @click="toggleResults('media')">
<i class="fas fa-chevron-circle-left" :class="mediaOpen && 'open'"></i>
<span>نتایج جستجو در رسانه:</span>
<b>{{ result.media.length }}</b>
</h2>
<p v-if="!result.media.length">هیچ نتیجه ای پیدا نشد.</p>
</div>
</div>
<!----------------------- Short result ------------------------->
<div class="row align-items-stretch">
<div class="col-12 col-md-6 col-lg-3 mb-3" v-for="(item,index) in result.media" :key="item._id" :title="item.title" v-if="index < 4">
<div class="media-item">
<img :src="item.thumbCover" :alt="item.title">
<div class="txtBox">
<h2>{{ item.title }}</h2>
<template v-if="item.galleryType === 'video'">
<nuxt-link class="btn btn-primary" :to="{name: 'portal-videos-video',params: {portal: item.modelType,video: item._id}}">ادامه مطلب</nuxt-link>
<span class="tag">فیلم</span>
</template>
<template v-if="item.galleryType === 'image'">
<nuxt-link class="btn btn-primary" :to="{name: 'portal-gallery-media',params: {portal: item.modelType,media: item._id}}">ادامه مطلب</nuxt-link>
<span class="tag">تصویر</span>
</template>
<template v-if="item.galleryType === 'graphic'">
<nuxt-link class="btn btn-primary" :to="{name: 'portal-graphics-graphic',params: {portal: item.modelType,graphic: item._id}}">ادامه مطلب</nuxt-link>
<span class="tag">گرافیک</span>
</template>
</div>
</div>
</div>
</div>
<!----------------------- Short result ------------------------->
<!----------------------- Full result ------------------------->
<div class="row align-items-stretch results">
<div class="col-12 col-md-6 col-lg-3 mb-3" v-for="(item,index) in result.media" :key="item._id" :title="item.title" v-if="index >= 4">
<div class="media-item">
<img :src="item.thumbCover" :alt="item.title">
<div class="txtBox">
<h2>{{ item.title }}</h2>
<template v-if="item.galleryType === 'video'">
<nuxt-link class="btn btn-primary" :to="{name: 'portal-videos-video',params: {portal: item.modelType,video: item._id}}">ادامه مطلب</nuxt-link>
<span class="tag">فیلم</span>
</template>
<template v-if="item.galleryType === 'image'">
<nuxt-link class="btn btn-primary" :to="{name: 'portal-gallery-media',params: {portal: item.modelType,media: item._id}}">ادامه مطلب</nuxt-link>
<span class="tag">تصویر</span>
</template>
<template v-if="item.galleryType === 'graphic'">
<nuxt-link class="btn btn-primary" :to="{name: 'portal-graphics-graphic',params: {portal: item.modelType,graphic: item._id}}">ادامه مطلب</nuxt-link>
<span class="tag">گرافیک</span>
</template>
</div>
</div>
</div>
</div>
<!----------------------- Full result ------------------------->
<div class="row seeMore" v-if="result.media.length > 4">
<!-- <div class="col-12 mt-4">-->
<!-- <div class="line"></div>-->
<!-- </div>-->
<div class="col-12">
<button @click="toggleResults('media')">
<span v-if="!mediaOpen">نتایج بیشتر</span>
<span v-else>نتایج کمتر</span>
<i class="fas fa-chevron-double-down" :class="mediaOpen && 'open'"></i>
</button>
</div>
</div>
</div>
</section>
</div>
</template>
<script>
export default {
data() {
return {
result: null,
newsOpen: false,
pagesOpen: false,
mediaOpen: false
}
},
computed: {
searchQuery() {
return this.$route.query.sq
}
},
watch: {
searchQuery(newVal, oldVal) {
this.$nuxt.refresh()
}
},
mounted() {
$(document).ready(() => {
$('.search-result .results').slideUp()
})
},
methods: {
toggleResults(item) {
if (item === 'news') this.newsOpen = !this.newsOpen
if (item === 'pages') this.pagesOpen = !this.pagesOpen
if (item === 'media') this.mediaOpen = !this.mediaOpen
$(`.search-result .${item} .results`).slideToggle(500)
},
categoryURLQuery(item) {
const query = {type: item.defaultPageType, id: item._id}
if (item.defaultPageType === 'news') return {...query, page: 1}
if (item.defaultPageType === 'gallery-image') return {...query, page: 1, type: 'gallery', galleryType: 'image'}
if (item.defaultPageType === 'gallery-video') return {...query, page: 1, type: 'gallery', galleryType: 'video'}
if (item.defaultPageType === 'gallery-graphic') return {...query, page: 1, type: 'gallery', galleryType: 'graphic'}
else return query
}
},
async asyncData({$axios, error, query}) {
const searchQuery = query.sq
try {
if (searchQuery?.length) {
const result = await $axios.get('/api/public/search', {
params: {
terms: searchQuery
}
})
return {
result: result.data
}
} else {
return {
result: {
news: [],
media: [],
pages: []
}
}
}
} catch (e) {
error({status: 404})
}
}
}
</script>
+217
View File
@@ -0,0 +1,217 @@
<template>
<div class="election-page">
<div class="container" v-if="!loggedIn">
<div class="row login-row">
<div class="col-12 col-md-8">
<div class="view-form">
<img src="~/static/img/logo-re3-150x150.png" alt="">
<form @submit.prevent="post">
<h2 class="title">ورود</h2>
<div class="formRow" :class="validation.username ? 'err' : null">
<input class="input" v-model="loginData.username" name="userName" type="text" placeholder="ایمیل یا نام کاربری را وارد کنید"/>
<p v-if="validation.username">{{ validation.username.msg }}</p>
</div>
<div class="formRow" :class="validation.password ? 'err' : null">
<input class="input" v-model="loginData.password" name="password" type="password" placeholder="پسوورد خود را وارد کنید"/>
<p v-if="validation.password">{{ validation.password.msg }}</p>
</div>
<div class="btnSub">
<button class="btn btn-primary btn-link" type="submit">ورود</button>
<!-- <nuxt-link >SUBMIT NOW</nuxt-link> -->
</div>
</form>
</div>
</div>
</div>
</div>
<div class="container" v-else>
<div class="row">
<div class="col-12">
<LineTxt label="انتخابات"/>
</div>
<div class="col-12 stretch">
<div class="election-view-item">
<div class="election-item1">
<h2>{{ election.title }} :</h2>
<p class="about-title">درباره انتخابات :</p>
<p class="about-txt">{{ election.description }}</p>
</div>
<div class="row election-item2">
<div class="col-12 col-md-6 col-lg-4 col-xl-3" v-for="item in election.candidates">
<div class="election-user" :class="[selectedCandide === item._id ? 'selected' : 'exclude',selectedCandide && 'clicked']">
<img :src="item.profilePic" :alt="item.firstName + ' ' + item.lastName">
<h3 class="user-name">{{ item.firstName + ' ' + item.lastName }}</h3>
<div class="view-btn">
<button type="button" @click="itemDialog(item)" class="btn bigBtn btn-primary p-2">مشاهده رزومه</button>
<button class="btn bigBtn p-2" :class="selectedCandide === item._id ? 'selectBTN' : 'btn-success'" @click="selectedCandide = item._id">انتخاب</button>
</div>
</div>
</div>
<!------------------------ CV modal ------------------------>
<el-dialog :visible.sync="showAlert">
<div class="container">
<div class="row align-items-center mb-3">
<div class="col-12 col-md-4">
<img class="img-alert" :src="dialogData.profilePic" :alt="dialogData.firstName + ' ' + dialogData.lastName">
</div>
<div class="col-12 col-md-8">
<h2 class="user-name">{{ dialogData.firstName + ' ' + dialogData.lastName }}</h2>
<p>تاریخ تولد : {{ dialogData.bornDate }}</p>
<p>کد ملی : {{ dialogData.nationalCode }}</p>
<p>مدرک تحصیلی : {{ dialogData.education }}</p>
</div>
</div>
<div>
<h3 class="about"> رزومه :</h3>
<p>{{ dialogData.resume }}</p>
</div>
</div>
<div slot="footer" class="dialog-footer">
<el-button class="btn bigBtn btn-primary" @click="showAlert = false">بستن</el-button>
</div>
</el-dialog>
<!------------------------ CV modal ------------------------>
<div class="col-12">
<button class="btn bigBtn btn-primary pt-2 pb-2 voteBtn" :disabled="!selectedCandide" @click="vote">ثبت رای</button>
<button class="btn bigBtn btn-primary pt-2 pb-2" @click="logOutOfElection">خروج</button>
</div>
</div>
</div>
</div>
<div class="not-found" v-if="!election">
<p>موردی وجود ندارد!</p>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
showAlert: false,
loginData: {
username: '',
password: '',
},
validation: {},
election: null,
selectedCandide: '',
dialogData: {}
}
},
computed: {
loggedIn() {
return (this.$auth.loggedIn && this.$auth.hasScope('voter'))
}
},
methods: {
post() {
this.validation = {}
this.$auth.loginWith('vote', {
data: this.loginData
})
.then(res => {
this.loginData = {
username: '',
password: '',
}
this.$nuxt.refresh()
})
.catch(e => {
if (e.response.status === 422) this.validation = e.response.data.validation
else console.log(e)
})
},
itemDialog(item) {
this.showAlert = !this.showAlert
this.dialogData = item
},
vote() {
if (!this.selectedCandide.length) return this.$message({
type: 'warning',
message: 'ابتدا یک گزینه انتخاب کنید'
})
this.$confirm("از انتخاب خود اطمینان دارید؟", "هشدار", {
confirmButtonText: "بله",
cancelButtonText: "لغو",
type: "warning",
})
.then(() => {
this.$axios.post('/api/public/addVote', {
electionId: this.election._id,
candidateId: this.selectedCandide
})
.then(res => {
this.$message({
type: 'success',
message: 'انتخاب شما با موفقیت ثبت شد'
})
this.$auth.logout()
})
.catch(e => {
this.error({
status: 500, message: 'مشکلی در ارسال اطلاعات به وجود آمده است'
})
})
})
.catch(() => {
this.$message({
type: "warning",
message: "عملیات لغو شد",
});
})
},
logOutOfElection() {
this.$confirm("از صفحه انتخابات خارج میشوید؟", "هشدار", {
confirmButtonText: "بله",
cancelButtonText: "لغو",
type: "warning",
})
.then(() => {
this.$auth.logout()
})
.catch(() => {
this.$message({
type: "warning",
message: "عملیات لغو شد",
});
})
}
},
async asyncData({$axios, error, $auth}) {
try {
if ($auth.loggedIn && $auth.hasScope('voter')) {
const election = await $axios.get('/api/public/getElection')
return {
election: election.data,
}
} else {
return {
election: []
}
}
} catch (e) {
error({
status: 401, message: 'شما اجازه دسترسی به این صفحه را ندارید'
})
}
}
}
</script>
+33
View File
@@ -0,0 +1,33 @@
<template>
<div class="services-page">
<div class="container">
<div class="row">
<div class="col-12">
<LineTxt label="میز خدمت"/>
</div>
<div class="col-12 col-md-6 services-view">
<nuxt-link :to="{name: 'portal-services-election', params: {portal: currentPortal}}" class="services-item">
<i class="far fa-check-square"></i>
<span>شرکت در انتخابات استانداری مرکزی</span>
</nuxt-link>
</div>
<div class="col-12 col-md-6 services-view">
<nuxt-link :to="{name: 'portal-services-meeting', params: {portal: currentPortal}}" class="services-item">
<i class="far fa-check-square"></i>
<span>ارتباط با استاندار</span>
</nuxt-link>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
computed: {
currentPortal() {
return this.$route.params.portal
}
}
}
</script>
+138
View File
@@ -0,0 +1,138 @@
<template>
<div class="meeting-page">
<div class="container">
<div class="row">
<div class="col-12">
<LineTxt label="ارتباط با استاندار"/>
</div>
<div class="col-12 ">
<div class="view-form">
<form @submit.prevent="post">
<div class="formRow" :class="validation.name ? 'err' : null">
<input class="input" v-model="message.name" name="name" type="text" placeholder="نام و نام خانوادگی خود را وارد کنید"/>
<p v-if="validation.name">{{ validation.name.msg }}</p>
</div>
<div class="formRow" :class="validation.subject ? 'err' : null">
<input class="input" v-model="message.subject" name="subject" type="text" placeholder="موضوع خود را وارد کنید"/>
<p v-if="validation.subject">{{ validation.subject.msg }}</p>
</div>
<div class="formRow" :class="validation.description ? 'err' : null">
<input class="input" v-model="message.description" name="description" type="text" placeholder="توضیحات خود را وارد کنید"/>
<p v-if="validation.description">{{ validation.description.msg }}</p>
</div>
<div class="formRow" :class="validation.email ? 'err' : null">
<input class="input" v-model="message.email" name="email" type="email" placeholder="ایمیل خود را وارد کنید"/>
<p v-if="validation.email">{{ validation.email.msg }}</p>
</div>
<div class="formRow" :class="validation.phoneNumber ? 'err' : null">
<input class="input" v-model="message.phoneNumber" name="phoneNumber" type="text" placeholder="شماره تماس خود را وارد کنید"/>
<p v-if="validation.phoneNumber">{{ validation.phoneNumber.msg }}</p>
</div>
<div class="formRow" :class="validation.nationalCode ? 'err' : null">
<input class="input" v-model="message.nationalCode" name="nationalCode" type="text" placeholder="کدملی خود را وارد کنید"/>
<p v-if="validation.nationalCode">{{ validation.nationalCode.msg }}</p>
</div>
<div class="row view-captcha">
<div class="formRow col-12 col-md-6" :class="validation.captcha ? 'err' : null">
<input v-model="message.captcha" class="input" name="captcha" type="text" placeholder="متن داخل عکس را وارد کنید"/>
</div>
<div class="new-captcha col-12 col-md-6">
<div class="captcha" v-html="captcha"></div>
<button @click="reloadCaptcha" type="button" class="btn btn-primary">
<i class="fas fa-sync-alt"></i>
</button>
</div>
<p class="err-captcha" v-if="validation.captcha">{{ validation.captcha.msg }}</p>
</div>
<div class="btnSub">
<button class="btn btn-primary btn-link" type="submit">ثبت</button>
<!-- <nuxt-link >SUBMIT NOW</nuxt-link> -->
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
message: {
name: '',
subject: '',
description: '',
email: '',
phoneNumber: '',
nationalCode: '',
captcha: '',
},
validation: {},
captcha: null
}
},
methods: {
reloadCaptcha() {
this.$axios.get('/api/public/getCaptcha').then(res => {
this.captcha = res.data
})
},
post() {
this.validation = {}
this.$axios.post('/api/public/meetingOstandar', this.message)
.then(res => {
this.reloadCaptcha()
this.$message({
type: 'success',
message: 'پیام شما با موفقیت ارسال شد'
})
this.message = {
name: '',
subject: '',
description: '',
email: '',
phoneNumber: '',
nationalCode: '',
captcha: '',
}
})
.catch(e => {
this.reloadCaptcha()
if (e.response.status === 422) this.validation = e.response.data.validation
else console.log(e)
})
}
},
computed: {},
async asyncData({$axios, error, params}) {
try {
const request = [
$axios.get('/api/public/getCaptcha'),
]
let fetch = await Promise.all(request)
const [captcha] = fetch
return {
captcha: captcha.data,
}
} catch (e) {
error({
status: 500, message: 'دریافت اطلاعات با مشکل مواجه شد!'
})
}
}
}
</script>
+149
View File
@@ -0,0 +1,149 @@
<template>
<section class="video-details">
<div class="container">
<div class="row">
<div class="view-date">
<p class="date">{{ jalali(info.customDate || info.created_at) }}</p>
<p class="date">{{ jDate(info.customDate || info.created_at) }}</p>
</div>
<div v-if="info.summaryTitle" class="col-12 col-md-6">
<h2 class="summry-title mt-3">
{{ info.summaryTitle }}
</h2>
</div>
<div class="col-12">
<h1 class="title">
{{ info.title }}
</h1>
</div>
<div v-if="info.leadTitle" class="col-12">
<p class="summry-title mb-4">
{{ info.leadTitle }}
</p>
</div>
<div class="row mb-4">
<div class="col-12 img-video">
<div v-html="info.embeddedCode" v-if="info.isEmbedded"></div>
<video width="100%" controls :src="info.video" :poster="info.cover" v-else></video>
</div>
</div>
</div>
</div>
<div class="s2" v-if="related.length">
<h3>مطالب مرتبط</h3>
<div id="slides">
<div class="slide" v-for="item in related" :key="item._id">
<div class="view-txt">
<div>
<p class="h3">{{ item.title }}</p>
<p>{{ item.summaryTitle }}</p>
<div class="date">
<span>{{ jalali(item.customDate || item.created_at) }}</span>
<span>توسط {{ item._creator.firstName + ' ' + item._creator.lastName }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</template>
<script>
import moment from 'moment-jalaali'
if (process.client) require("slick-carousel")
export default {
data() {
return {
info: [],
galleryShown: false,
initialIndex: 0,
related: []
}
},
mounted() {
// $(document).ready(() => {
$("#slides").slick({
dots: true,
slidesToShow: this.related.length === 1 ? 1 : 2,
rtl: true,
responsive: [
{
breakpoint: 960,
settings: {
slidesToShow: 2,
slidesToScroll: 1,
infinite: true,
dots: true
}
},
{
breakpoint: 720,
settings: {
slidesToShow: 2,
slidesToScroll: 1
}
},
{
breakpoint: 540,
settings: {
slidesToShow: 1,
slidesToScroll: 1
}
}
]
})
// })
},
methods: {
jalali(date) {
return moment(date).locale('fa').fromNow()
},
jDate(date) {
return moment(date).locale('fa').format('LL')
}
},
head() {
return {
title: 'جزئیات فیلم',
meta: [
{
hid: 'description',
name: 'description',
content: this.info.summaryTitle
},
{
hid: 'keywords',
name: 'keywords',
content: this.info.keywords
}
]
}
},
async asyncData({params, error, $axios}) {
try {
let data = await $axios.get(`/api/public/getGallery/${encodeURIComponent(params.video)}`)
let related = await $axios.get(`/api/public/getRelatedGallery`, {
params: {
type: 'video',
title: params.video
}
})
return {
info: data.data,
related: related.data
}
} catch (err) {
error({status: 404, message: 'دریافت اطلاعات با مشکل مواجه شده است!'})
}
}
}
</script>
+131
View File
@@ -0,0 +1,131 @@
<template>
<div class="video-page">
<div class="container">
<div class="row">
<div class="col-12 col-md-9">
<h3 class="video-title">فیلم</h3>
<div class="">
<div class="row">
<div class="col-12 mb-5 sectionStyle" v-if="video.all.docs.length" >
<div class="video-item1">
<nuxt-link :to="{name: 'portal-videos-video', params: {portal: currentPortal, video: video.all.docs[0]._id}}" class="video-img-box1">
<img :src="video.all.docs[0].thumbCover" alt="" class="video-img1">
<div class="video-detail-item1">
<h3 class="video-detail-title1">{{ video.all.docs[0].title }}</h3>
<p class="video-detail-date1" id="video-detail-date1">{{ jDate(video.all.docs[0].customDate || video.all.docs[0].created_at) }}</p>
</div>
</nuxt-link>
</div>
</div>
<div class="col-12">
<div class="not-found" v-if="!video.all.docs.length">
<p>موردی وجود ندارد!</p>
</div>
</div>
<div class="col-12 col-sm-6 col-md-3 mb-3 sectionStyle" v-for="(item, index) in video.all.docs" :key="item.id" v-if="index > 0 && video.all.docs.length">
<div class="video-item">
<nuxt-link :to="{name: 'portal-videos-video', params: {portal: currentPortal, video: item._id}}" class="video-img-box">
<img :src="item.thumbCover" alt="" class="video-img">
</nuxt-link>
<div class="video-detail-item">
<h3 class="video-detail-title">{{ item.title }}</h3>
<p class="video-detail-date" id="video-detail-date">{{ jDate(item.customDate || item.created_at) }}</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-12 col-md-3">
<h3 class="video-side">برگزیده ها</h3>
<div class="sectionStyle" v-if="video.favorites.length">
<div class="row">
<div class="col-12 col-sm-6 col-md-12 mb-3" v-for="(item, index) in video.favorites" :key="item.id" v-if="index < 5">
<div class="video-item ">
<nuxt-link :to="{name: 'portal-videos-video', params: {portal: currentPortal, video: item._id}}" class="video-img-box">
<img :src="item.thumbCover" alt="" class="video-img">
</nuxt-link>
<div class="video-detail-item">
<h3 class="video-detail-title">{{ item.title }}</h3>
<p class="video-detail-date" id="video-detail-date2">{{ jDate(item.customDate || item.created_at) }}</p>
</div>
</div>
</div>
</div>
</div>
<div class="not-found" v-if="!video.favorites.length">
<p>موردی وجود ندارد!</p>
</div>
</div>
</div>
<div class="paginate">
<div class="row">
<div class="col-12">
<el-pagination
layout="next, pager, prev"
v-if="video.all.totalPages > 1"
class="el-pagination"
@current-change="pageNumber"
:current-page="Number($route.query.page)"
:page-count="Number(video.all.totalPages)"
>
</el-pagination>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import moment from "moment-jalaali"
export default {
data() {
return {
video: null
}
},
computed: {
currentPortal() {
return this.$route.params.portal
},
pageQuery() {
return this.$route.query.page
},
},
watch: {
pageQuery(newVal, oldVal) {
this.$nuxt.refresh()
},
},
methods: {
jDate(date) {
return moment(date).locale('fa').format('LL')
},
pageNumber(val) {
this.$router.push({
name: 'portal-videos',
params: {portal: this.currentPortal},
query: {type: 'video', page: val}
})
$(window).scrollTop(0)
},
},
async asyncData({params, query, error, $axios}) {
// return error({status: 404})
try {
const portalQuery = params.portal
// const data = await $axios.get(`/api/public/getvideoCat/${query.category}`, {
const data = await $axios.get(`/api/public/getAllGallery?portal=${portalQuery}&type=${query.type}&page=${query.page}`)
// console.log('data.data', data.data.all)
return {
video: data.data
}
} catch (e) {
error({status: 404})
}
}
}
</script>
+120
View File
@@ -0,0 +1,120 @@
<template>
<CRow class="justify-content-center">
<CCol lg="5">
<CCardGroup>
<CCard class="p-4">
<CCardBody>
<CForm @submit.prevent="doLogin">
<h1 class="text-muted text-center mb-5">پنل مدیریت</h1>
<CInput
:class="validation.username ? 'err' : null"
placeholder="نام کاربری"
:description="validation.username ? validation.username.msg : null"
autocomplete="username email"
v-model="login.username"
>
<template #prepend-content>
<CIcon name="cil-user"/>
</template>
</CInput>
<div class="butt">
<CInput
:class="validation.password ? 'err' : null"
placeholder="کلمه عبور"
:type="passwordState"
:description="validation.password ? validation.password.msg : null"
autocomplete="curent-password"
v-model="login.password"
>
<template #prepend-content>
<CIcon name="cil-lock-locked"/>
</template>
</CInput>
<i @click="showPass = !showPass" class="far fa-eye"></i>
</div>
<CInputCheckbox label="مرا به خاطر بسپار" @update:checked="val => login.remember_me = val"/>
<p class="text-muted mt-3" style="font-size: 11px;">*درصورتی که گزینه "مرا به خاطر بسپار" را فعال نکنید بعد از 1 ساعت باید دوباره وارد سیستم شوید.</p>
<CRow>
<CCol col="12" class="text-right mt-2">
<CButton color="primary" type="submit" class="px-4">ورود</CButton>
</CCol>
</CRow>
</CForm>
</CCardBody>
</CCard>
</CCardGroup>
</CCol>
</CRow>
</template>
<script>
export default {
data() {
return {
showPass: false,
login: {
username: '',
password: '',
remember_me: false
},
validation: {}
}
},
computed: {
passwordState() {
return this.showPass ? "text" : "password"
}
},
methods: {
doLogin() {
this.validation = {}
this.$auth.loginWith('local', {
data: this.login
})
.then(response => {
window.location.replace('/admin')
})
.catch(err => {
if (err.response.status === 422) this.validation = err.response.data.validation
if (err.response.status === 403) {
this.$message({
type: 'warning',
message: err.response.data.message
})
} else console.log(err.response.data)
})
}
},
layout: 'admin-auth'
}
</script>
<style lang="scss">
.butt {
position: relative;
i {
position: absolute;
left: 7px;
top: 11px;
z-index: 3;
cursor: pointer;
color: rgba(#000, 0.5);
-webkit-transition: 0.2s;
-moz-transition: 0.2s;
-ms-transition: 0.2s;
-o-transition: 0.2s;
transition: 0.2s;
&:hover {
color: #000;
}
}
}
</style>
+73
View File
@@ -0,0 +1,73 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="primary" class="mr-auto" :to="{ name: 'admin' }">برگشت به صفحه داشبورد</CButton>
</CustomSubHeader>
<CCard>
<CCardBody>
<CRow>
<CCol>
<h2>پشتیبان گیری</h2>
<el-divider></el-divider>
<a :href="`/api/public/backup/${$auth.user.token}`" target="_blank">
<el-button type="success">تهیه و دریافت فایل پشتیبان</el-button>
</a>
<el-button type="danger" @click="clearBackups">پاک کردن فایل های بکاپ آپ قبلی</el-button>
</CCol>
</CRow>
</CCardBody>
</CCard>
</div>
</template>
<script>
export default {
data() {
return {
title: 'پشتیبان گیری از اطلاعات سایت'
}
},
head() {
return {
title: this.title
}
},
methods: {
// getBackup() {
// const loading = this.$loading({
// lock: true,
// text: 'سایت در حال پشتیبان گیری میباشد',
// spinner: 'el-icon-loading',
// background: 'rgba(0, 0, 0, 0.7)'
// })
//
// this.$axios.get(`/api/public/backup/${this.$auth.user.token}`)
// .then(res => {
// loading.close()
// console.log(res.data)
// })
// .catch(err => {
// loading.close()
// console.log(err)
// })
// },
clearBackups() {
this.$axios.post('/api/admin/clearBackups')
.then(res => {
this.$message({
type: 'success',
message: 'فایل های پشتیبان قبلی با موفقیت از روی سیستم حذف شدند'
})
})
.catch(err => {
this.$message({
type: 'error',
message: 'مشکلی در اجرای عملیات پیش آمده، لطفا دوباره امتحان کنید.'
})
})
}
},
layout: "admin"
}
</script>
+203
View File
@@ -0,0 +1,203 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="primary" class="mr-auto" :to="{ name: 'admin-comments-type' , params : {type : $route.params.type} }">برگشت به صفحه قبل</CButton>
<CButton size="sm" color="success" class="mr-1" @click="update">بروزرسانی</CButton>
</CustomSubHeader>
<CRow style="display : flex ; flex-direction: column">
<CRow>
<CCol lg="6">
<CCard>
<CCardBody>
<CCol sm="12">
<CInput
label="نام و نام خانوادگی"
:class="validation.name ? 'err' : null"
:description="validation.name ? validation.name.msg : null"
:value="comment.name"
disabled
/>
</CCol>
<el-divider></el-divider>
<CCol sm="12">
<CInput
label="ایمیل"
:class="validation.email ? 'err' : null"
:description="validation.email ? validation.email.msg : null"
:value="comment.email"
disabled
/>
</CCol>
<el-divider></el-divider>
<CCol sm="12">
<CTextarea
label="متن پیام"
:class="validation.description ? 'err' : null"
:description="validation.description ? validation.title.msg : null"
:value="comment.description"
disabled
/>
</CCol>
</CCardBody>
</CCard>
</CCol>
<template v-if="$route.params.type==='News'">
<CCol lg="6">
<CCard>
<CCardBody>
<CCol sm="12">
<el-button type="primary" size="mini" plain icon="el-icon-search" @click="showNews = true">
جزئیات خبر
</el-button>
<el-dialog title="جزئیات خبر" :visible.sync="showNews">
<CContainer style="border: solid 1px;padding: 25px;border-radius: 15px;">
<CRow style="flex-direction: column;">
<CCol>
<h5 style="text-align: justify; word-break: break-word;">{{ comment.modelRef.title }}</h5>
</CCol>
<CCol class="mt-3">
<p style="text-align: justify; word-break: break-word;">{{ comment.modelRef.summaryTitle }}</p>
</CCol>
<CCol class="mt-3">
<img width="100%" :src="comment.modelRef.cover" alt=""/>
</CCol>
<CCol class="mt-3">
<div v-html="comment.modelRef.pageContent">
</div>
</CCol>
</CRow>
</CContainer>
</el-dialog>
</CCol>
<el-divider></el-divider>
<CCol sm="12">
<el-checkbox
v-model="comment.allowShow"
label="پیام مورد تایید می باشد"
/>
</CCol>
</CCardBody>
</CCard>
</CCol>
</template>
</CRow>
</CRow>
</div>
</template>
<script>
import axiosUploadProcess from "@/mixins/axiosUploadProcess";
import unreadNewsMessages from "@/mixins/unreadNewsMessages"
import unreadContactMessages from "@/mixins/unreadContactMessages"
export default {
data() {
return {
comment: null,
showNews: false,
validation: {}
};
},
mixins: [axiosUploadProcess, unreadNewsMessages, unreadContactMessages],
computed: {
title() {
return "مشاهده جزئیات پیام";
},
},
methods: {
imagePreview(e) {
this.comment.cover = URL.createObjectURL(e.target.files[0]);
},
update() {
this.validation = {};
const data = new FormData();
data.append("name", this.comment.name.trim());
data.append("description", this.comment.description.trim());
data.append("email", this.comment.email);
data.append("allowShow", this.comment.allowShow);
this.$axios
.put(`/api/admin/comment/${this.$route.params.type}/${this.comment._id}`, data, this.axiosConfig)
.then((response) => {
this.$message({
type: "success",
message: "اطلاعات بروزرسانی شد.",
});
this.$router.push({
name: "admin-comments-type",
params: {type: this.$route.params.type}
});
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
if (err.response.status === 500) {
return this.$message({
type: "error",
message: "مشکلی در ارسال درخواست پیش آمده",
});
}
if (err.response.status === 422)
this.validation = err.response.data.validation;
else console.log(err.response.data);
});
},
},
head() {
return {
title: this.title,
};
},
layout: "admin",
async asyncData({
$axios,
$auth,
params,
query,
error
}) {
try {
const comment = await $axios.get(`/api/admin/comment/${params.type}/${params.details}`);
return {
comment: comment.data
};
} catch (e) {
if (e?.response?.status === 401) {
error({
status: 401,
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (e?.response?.status === 403) {
error({
status: 403,
message: e?.response?.data?.message,
});
}
if (e?.response?.status === 500) {
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات پیش آمده",
});
} else
error({
status: 404,
message: "پیام مورد نظر پیدا نشد",
});
}
},
};
</script>
+347
View File
@@ -0,0 +1,347 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
</CustomSubHeader>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-filter"></i>
<span style="color:#000">فیلتر</span>
</slot>
</CCardHeader>
<CCardBody>
<CRow>
<CCol md="6">
<CRow style="flex-direction : column;">
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>نام و نام خانوادگی</span>
</CCol>
<CCol col="md-9">
<el-input style="width : 100%" placeholder="" v-model="search.name"></el-input>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>ایمیل</span>
</CCol>
<CCol col="md-9">
<el-input style="width : 100%" placeholder="" v-model="search.email"></el-input>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>تاریخ</span>
</CCol>
<CCol col="md-9">
<date-picker range clearable format="YYYY-MM-DD" display-format="jMMMM jD" v-model="search.date"></date-picker>
</CCol>
</CRow>
</CCol>
</CRow>
</CCol>
<CCol md="6">
<CRow style="flex-direction : column;">
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>وضعیت پیام</span>
</CCol>
<CCol col="md-9">
<el-select v-model="search.read" clearable style="width : 100%">
<el-option :key="true" label="خوانده شده" :value="true">
</el-option>
<el-option :key="false" label="خوانده نشده" :value="false">
</el-option>
</el-select>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>وضعیت تایید</span>
</CCol>
<CCol col="md-9">
<el-select v-model="search.allowShow" clearable style="width : 100%">
<el-option :key="true" label="تایید شده" :value="true">
</el-option>
<el-option :key="false" label="تایید نشده" :value="false">
</el-option>
</el-select>
</CCol>
</CRow>
</CCol>
</CRow>
</CCol>
</CRow>
<CRow>
<el-button :loading="loading" @click="handleSearch" size="small" style="width: auto;margin: 25px auto auto auto;" type="primary"
icon="el-icon-search">
جست و جو</el-button>
</CRow>
</CCardBody>
</CCard>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>{{ list_title }}</span>
</slot>
<slot> </slot>
</CCardHeader>
<CCardBody>
<el-table v-loading="loading" :data="comment.docs" :default-sort="{ prop: 'date', order: 'descending' }" style="width: 100%">
<el-table-column type="index" label="#"> </el-table-column>
<el-table-column label="نام و نام خانوادگی" width="">
<template slot-scope="scope">
<span>{{ scope.row.name }}</span>
</template>
</el-table-column>
<el-table-column label="ایمیل" width="">
<template slot-scope="scope">
<span>{{ scope.row.email }}</span>
</template>
</el-table-column>
<el-table-column v-if="$route.params.type === 'News'" label="خبر" width="180px">
<template slot-scope="scope">
<el-button type="primary" size="mini" plain icon="el-icon-search" @click="openDialog(scope.row.modelRef)">
جزئیات خبر
</el-button>
</template>
</el-table-column>
<el-table-column label="وضعیت پیام" width="">
<template slot-scope="scope">
<el-tag :type="scope.row.read ? 'success' : 'danger'">
{{ scope.row.read ? 'خوانده شده' : 'خوانده نشده' }}
</el-tag>
</template>
</el-table-column>
<el-table-column v-if="$route.params.type === 'News'" label="وضعیت تایید">
<template slot-scope="scope">
<el-tag :type="scope.row.allowShow ? 'success' : 'danger'">
{{ scope.row.allowShow ? 'تایید شده' : 'تایید نشده' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="تاریخ ایجاد" width="">
<template slot-scope="scope">
<span>{{ jDate(scope.row.created_at) }}</span>
</template>
</el-table-column>
<el-table-column label="ویرایش" width="110" align="center">
<template slot-scope="scope">
<CButton color="danger" variant="outline" :key="scope.row._id + Math.random()"
@click="deleteSlider(scope.row._id)">
<i class="far fa-trash-alt"></i>
</CButton>
<CButton color="success" variant="outline" :key="scope.row._id" :to="{
name: `admin-comments-type-details`,
params: {type : $route.params.type , details: scope.row._id },
}">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
<CCard class="col" v-if="comment.totalDocs>5">
<CRow alignHorizontal="center" style="padding : 10px">
<el-pagination :hide-on-single-page="true" layout="prev, pager, next" :page-size="comment.limit"
@current-change="handleCurrentChange" :current-page.sync="comment.page" :total="comment.totalDocs">
</el-pagination>
</CRow>
</CCard>
<el-dialog title="جزئیات خبر" :visible.sync="showNews">
<CContainer style="border: solid 1px;padding: 25px;border-radius: 15px;">
<CRow style="flex-direction: column;">
<CCol>
<h5 style="text-align: justify; word-break: break-word;">{{newsDetails.title}}</h5>
</CCol>
<CCol class="mt-3">
<p style="text-align: justify; word-break: break-word;">{{newsDetails.summaryTitle}}</p>
</CCol>
<CCol class="mt-3">
<img width="100%" :src="newsDetails.cover" />
</CCol>
<CCol class="mt-3">
<div v-html="newsDetails.pageContent">
</div>
</CCol>
</CRow>
</CContainer>
</el-dialog>
</div>
</template>
<script>
import moment from "moment-jalaali";
const _ = require('lodash');
export default {
data() {
return {
title: "لیست پیام",
list_title: "لیست",
comment: null,
search: {},
showNews: false,
newsDetails: '',
loading : false
};
},
computed: {
pageQuery() {
return this.$route.query.page;
}
},
watch: {
pageQuery(newPage, oldPage) {
this.$nuxt.refresh();
}
},
methods: {
jDate(date) {
return moment(date).format("jYYYY/jMM/jDD");
},
openDialog(data) {
this.showNews = !this.showNews;
this.newsDetails = data;
},
handleCurrentChange(page) {
if (!_.isEmpty(this.search)) {
this.handleSearch(page);
} else {
this.$router.push({
name: "admin-comments-type",
params : {type : this.$route.params.type},
query: {
page: page
}
});
}
},
handleSearch(page) {
this.loading = true;
const data = {
name: this.search.name,
email: this.search.email,
read: this.search.read,
allowShow: this.search.allowShow,
date: this.search.date
}
this.$axios.post(`/api/admin/comment/${this.$route.params.type}/search?page=${page}`, data, this.axiosConfig)
.then((result) => {
this.comment = result.data;
this.loading = false;
})
.catch(err => {
this.loading = false;
if (err.response.status === 401) {
return this.$message({
type: 'error',
message: 'لطفا دوباره وارد سیستم شوید.'
})
}
if (err.response.status === 422) this.validation = err.response.data.validation
else console.log(err.response.data)
})
},
deleteSlider(id) {
this.$confirm("پیام حذف شود؟", "هشدار", {
confirmButtonText: "بله",
cancelButtonText: "لغو",
type: "warning",
})
.then(async () => {
this.$axios
.delete(`/api/admin/comment/${this.$route.params.type}/${id}`)
.then((res) => {
this.$message({
type: "success",
message: "پیام با موفقیت حذف شد",
});
this.$nuxt.refresh();
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
if (err.response.status === 422) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
console.log(err.response.data);
});
})
.catch(() => {
this.$message({
type: "warning",
message: "عملیات لغو شد",
});
});
},
},
head() {
return {
title: this.title,
};
},
layout: "admin",
async asyncData({
$axios,
params,
query,
error
}) {
try {
const comment = await $axios.get(`/api/admin/comment/${params.type}?page=${query.page}`);
return {
comment: comment.data,
};
} catch (e) {
if(e?.response?.status === 401){
error({
status: 401,
message: 'شما اجازه دسترسی به این صفحه را ندارید'
})
}else{
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات بوجود آمده است",
});
}
}
},
};
</script>
+152
View File
@@ -0,0 +1,152 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="primary" class="mr-auto" :to="{ name: 'admin-contact' }">برگشت به صفحه قبل
</CButton>
<CButton size="sm" color="success" class="mr-1" @click="update">بروزرسانی</CButton>
</CustomSubHeader>
<CRow style="display : flex ; flex-direction: column">
<CRow>
<CCol lg="6">
<CCard>
<CCardBody>
<CCol sm="12">
<CInput :class="validation.email ? 'err' : null" label="ایمیل" :description="
validation.email ? validation.email.msg : null
" v-model="contact.email" />
</CCol>
<el-divider></el-divider>
<CCol sm="12">
<CInput :class="validation.phone ? 'err' : null" label="شماره تماس" :description="
validation.phone ? validation.phone.msg : null
" v-model="contact.phone" />
</CCol>
<el-divider></el-divider>
<CCol sm="12">
<CTextarea :class="validation.address ? 'err' : null" label="آدرس" :description="
validation.address ? validation.address.msg : null
" v-model="contact.address" />
</CCol>
</CCardBody>
</CCard>
</CCol>
<CCol lg="6">
<CCard>
<CCardBody>
</CCardBody>
</CCard>
</CCol>
</CRow>
</CRow>
</div>
</template>
<script>
import axiosUploadProcess from "@/mixins/axiosUploadProcess";
export default {
data() {
return {
contact: null,
validation: {},
editorConfig: {
language: "en",
extraPlugins: ["bidi", "justify"],
}
};
},
mixins: [axiosUploadProcess],
computed: {
title() {
return 'مشاهده صفحه ارتباط با ما'
},
},
methods: {
imagePreview(e) {
this.contact.cover = URL.createObjectURL(e.target.files[0]);
},
update() {
this.validation = {};
const data = new FormData();
data.append("title", this.contact.title);
data.append("summaryTitle", this.contact.summaryTitle);
data.append("catId", this.contact.catId);
data.append("priority", this.contact.priority);
data.append("allowComment", this.contact.allowComment);
data.append("showInHome", this.contact.showInHome);
data.append("slider", this.contact.slider);
data.append("publish", this.contact.publish);
data.append("pageContent", this.contact.pageContent);
data.append("special", this.contact.special);
data.append("notifications", this.contact.notifications);
data.append("keywords", JSON.stringify(this.contact.keywords));
data.append("metaTagDesc", this.contact.summaryTitle);
data.append("modelType", this.contact.modelType);
this.$axios
.put(`/api/admin/contact/${this.contact._id}`, data, this.axiosConfig)
.then((response) => {
this.$message({
type: "success",
message: "اطلاعات بروزرسانی شد.",
});
this.$nuxt.refresh();
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
if (err.response.status === 500) {
return this.$message({
type: "error",
message: "مشکلی در ارسال درخواست پیش آمده",
});
}
if (err.response.status === 422)
this.validation = err.response.data.validation;
else console.log(err.response.data);
});
},
},
head() {
return {
title: this.title,
};
},
layout: "admin",
async asyncData({
$axios,
$auth,
params,
query,
error
}) {
try {
const contact = await $axios.get(`/api/admin/contactUs`);
return {
contact: contact.data
};
} catch (e) {
console.log(e);
error({
status: 404,
message: "contact not found",
});
}
},
};
</script>
+330
View File
@@ -0,0 +1,330 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="primary" class="mr-auto" :to="{ name: 'admin' }">برگشت به صفحه اصلی داشبورد</CButton>
<CButton v-if="!exist" size="sm" color="success" class="mr-1" @click="post">بروزرسانی</CButton>
<CButton v-else size="sm" color="success" class="mr-1" @click="update">بروزرسانی</CButton>
</CustomSubHeader>
<CRow>
<template v-if="manager">
<CCol lg="6">
<CCard>
<CCardBody>
<CCol sm="12">
<CInput
:class="validation.title ? 'err' : null"
label="نام و نام خانوادگی"
:description="validation.title ? validation.title.msg : null"
v-model="page.title"
/>
</CCol>
<CCol sm="12">
<CInput
:class="validation.email ? 'err' : null"
label="ایمیل"
:description="validation.email ? validation.email.msg : null"
v-model="page.email"
/>
</CCol>
</CCardBody>
</CCard>
</CCol>
<CCol lg="6">
<CCard>
<CCardBody>
<CCol sm="12">
<h5>عکس مدیر سازمان</h5>
<el-divider/>
<CCol>
<img
:src="page.cover"
style="width: 50%;"
alt=""
/>
</CCol>
<input type="file" ref="cover" @change="imagePreview"/>
<p
style="margin-top : 5px !important ;"
class="form-err"
v-if="validation.cover"
>
{{ validation.cover.msg }}
</p>
<p class="mt-3 text-muted">
<!-- عکس 500*500 باشد. در غیر این صورت اتوماتیک بریده می شود.-->
</p>
</CCol>
</CCardBody>
</CCard>
</CCol>
</template>
<template v-if="sima">
<CCol lg="12">
<CCard>
<CCardBody>
<CCol sm="12">
<el-checkbox v-model="page.showInMenu" label="این صفحه در منوی سایت نمایش داده شود"/>
</CCol>
</CCardBody>
</CCard>
</CCol>
</template>
<CCol>
<CCard>
<CCardBody>
<CCol sm="12" class="mb-3">
<template>
<client-only>
<p>محتوا صفحه</p>
<ckeditor
v-model="page.pageContent"
:config="editorConfig"
></ckeditor>
<p class="text-danger" v-if="validation.pageContent">
{{ validation.pageContent.msg }}
</p>
</client-only>
</template>
</CCol>
</CCardBody>
</CCard>
</CCol>
</CRow>
</div>
</template>
<script>
import axiosUploadProcess from "@/mixins/axiosUploadProcess";
export default {
data() {
return {
page: null,
exist: false,
manager: false,
sima: false,
validation: {},
editorConfig: {
language: "en",
extraPlugins: ["bidi", "justify"],
}
};
},
mixins: [axiosUploadProcess],
computed: {
title() {
if (!this.manager) {
return this.page.title
} else {
return 'مدیر سازمان'
}
},
},
methods: {
imagePreview(e) {
this.page.cover = URL.createObjectURL(e.target.files[0]);
},
post() {
this.validation = {};
const data = new FormData();
data.append("title", this.page.title.trim());
if (this.manager) data.append("email", this.page.email);
data.append("param", this.$route.params.details);
data.append("pageContent", this.page.pageContent);
if (this.manager) {
if (this.$refs.cover.files[0])
data.append("cover", this.$refs.cover.files[0]);
}
if (this.sima) {
data.append("showInMenu", this.page.showInMenu);
}
this.$axios
.post(`/api/admin/content`, data, this.axiosConfig)
.then((response) => {
this.$message({
type: "success",
message: "صفحه با موفقیت ایجاد شد.",
});
this.$nuxt.refresh();
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
if (err.response.status === 500) {
return this.$message({
type: "error",
message: "مشکلی در ارسال درخواست پیش آمده",
});
}
if (err.response.status === 422)
this.validation = err.response.data.validation;
else console.log(err.response.data);
});
},
update() {
this.validation = {};
const data = new FormData();
data.append("title", this.page.title.trim());
if (this.manager) data.append("email", this.page.email);
data.append("param", this.$route.params.details);
data.append("pageContent", this.page.pageContent);
if (this.manager) {
if (this.$refs.cover.files[0])
data.append("cover", this.$refs.cover.files[0]);
}
if (this.sima) {
data.append("showInMenu", this.page.showInMenu);
}
this.$axios
.put(`/api/admin/content/${this.$route.params.details}`, data, this.axiosConfig)
.then((response) => {
this.$message({
type: "success",
message: "اطلاعات بروزرسانی شد.",
});
this.$nuxt.refresh();
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
if (err.response.status === 500) {
return this.$message({
type: "error",
message: "مشکلی در ارسال درخواست پیش آمده",
});
}
if (err.response.status === 422)
this.validation = err.response.data.validation;
else console.log(err.response.data);
});
},
},
head() {
return {
title: this.title,
};
},
layout: "admin",
async asyncData({$axios, params, error}) {
try {
const page = await $axios.get(`/api/admin/content/${params.details}`);
let title;
let manager = false;
let sima = false;
switch (params.details) {
case 'aboutState':
title = 'درباره استان'
break;
case 'sima':
title = 'سیمای استان'
sima = true;
break;
case 'performance':
title = 'عملکرد'
break;
case 'aboutus':
title = 'درباره ما'
break;
case 'services':
title = 'خدمات'
break;
case 'terms':
title = 'شرایط استفاده'
break;
case 'privacy':
title = 'حفظ حریم خصوصی'
break;
case 'cookies':
title = 'کوکی ها'
break;
case 'facilities':
title = 'امکانات'
break;
case 'layout':
title = 'صفحه آرایی'
break;
case 'faq':
title = 'سوالات متداول'
break;
case 'rules':
title = 'قوانین و مقررات'
break;
case 'sitemap':
title = 'نقشه سایت'
break;
case 'manager':
manager = true;
title = '';
break;
default:
title = 'صفحه'
break;
}
if (page.data) {
return {
exist: true,
manager,
sima,
page: page.data,
};
} else {
return {
exist: false,
manager,
sima,
page: {
title: title,
email: '',
param: params.details,
pageContent: '',
cover: ''
}
};
}
} catch (e) {
if (e?.response?.status === 401) {
error({
status: 401,
message: 'شما اجازه دسترسی به این صفحه را ندارید'
})
} else {
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات بوجود آمده است",
});
}
}
},
};
</script>
+140
View File
@@ -0,0 +1,140 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="success" class="mr-auto" @click="update">بروزرسانی</CButton>
</CustomSubHeader>
<CCard>
<CCardBody>
<CRow>
<CCol sm="12" md="6">
<CInput
:class="validation.title ? 'err' : null"
label="عنوان"
:description="validation.title ? validation.title.msg : null"
v-model="counterDay.title"
/>
</CCol>
<CCol sm="12" md="6">
<p class="mb-2" style="color: #666666; font-size: 14px !important;">تاریخ اتمام</p>
<date-picker clearable :min="startDate" format="YYYY-MM-DD" display-format="jMMMM jD"
v-model="expireDate"></date-picker>
<p style="margin-top : 5px !important ; color: red; font-size: 12px !important;" class="form-err" v-if="validation.expireDate">
{{ validation.expireDate.msg }}
</p>
</CCol>
<el-divider></el-divider>
<CCol>
<el-checkbox
v-model="counterDay.publish"
label="نمایش داده شود"
/>
<p style="margin-top : 5px !important ; color: red;" class="form-err" v-if="validation.publish">
{{ validation.publish.msg }}
</p>
</CCol>
<el-divider></el-divider>
<CCol sm="12">
<span v-if="counterDay.title && counterDay.expireDate && new Date(counterDay.expireDate) > new Date()">{{ jDate(counterDay.expireDate) + ' مانده تا ' + counterDay.title }}</span>
</CCol>
</CRow>
</CCardBody>
</CCard>
</div>
</template>
<script>
import moment from "moment-jalaali";
export default {
data() {
return {
title: 'روز شمار',
counterDay: null,
validation: {}
}
},
computed:{
startDate(){
return moment().add(1, 'day').format('YYYY-MM-DD')
},
expireDate : {
get(){
return this.counterDay.expireDate ? moment(this.counterDay.expireDate).format('YYYY-MM-DD') : null
},
set(date){
this.counterDay.expireDate = date
}
}
},
methods: {
jDate(date) {
if (date){
return moment(date).locale('fa').fromNow(true)
}
},
update() {
this.validation = {}
const data = new FormData()
data.append('title', this.counterDay.title)
data.append('publish', this.counterDay.publish)
data.append('expireDate', this.expireDate)
this.$axios.post('/api/admin/counterDay', data, this.axiosConfig)
.then(res => {
this.$message({
type: 'success',
message: 'تغییرات با موفقیت انجام شد'
})
this.$nuxt.refresh()
})
.catch(err => {
if (err.response?.status === 422) {
this.validation = err.response.data.validation
this.$message({
type: 'warning',
message: 'پارامترها را بررسی کنید'
})
} else console.log(e)
})
}
},
head() {
return {
title: this.title,
};
},
layout: "admin",
async asyncData({$axios, error}) {
try {
const counterDay = await $axios.get('/api/admin/counterDay')
return {
counterDay: counterDay.data
}
} catch (e) {
if (e?.response?.status === 401) {
error({
status: 401,
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (e?.response?.status === 403) {
error({
status: 403,
message: e?.response?.data?.message,
});
}
if (e?.response?.status === 500) {
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات پیش آمده",
});
} else
error({
status: 404,
message: "اطلاعات مورد نظر پیدا نشد",
});
}
},
}
</script>
+99
View File
@@ -0,0 +1,99 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
</CustomSubHeader>
<CCard>
<CCardBody>
<CRow>
<CCol>
<el-checkbox label="نمایش دکمه سوییچ بین 'ستاد انتخابات' و 'استانداری'" v-model="yearBanner.electionBtn" @change="update"/>
</CCol>
</CRow>
</CCardBody>
</CCard>
</div>
</template>
<script>
export default {
data() {
return {
title: "دکمه سوییچ بین 'ستاد انتخابات' و 'استانداری'",
yearBanner: null,
}
},
methods: {
update() {
this.validation = {}
const data = {
iranFlag: this.yearBanner.iranFlag,
electionBtn: this.yearBanner.electionBtn,
// socialLinks
hasEmail: this.yearBanner.hasEmail,
hasGPlus: this.yearBanner.hasGPlus,
hasTweeter: this.yearBanner.hasTweeter,
hasInstagram: this.yearBanner.hasInstagram,
email: this.yearBanner.email,
gPlus: this.yearBanner.gPlus,
tweeter: this.yearBanner.tweeter,
instagram: this.yearBanner.instagram
}
this.$axios.post('/api/admin/yearBanner', data)
.then(res => {
this.$message({
type: 'success',
message: 'تغییرات با موفقیت انجام شد'
})
})
.catch(err => {
if (err.response?.status === 422) {
this.validations = err.response.data.validation
this.$message({
type: 'warning',
message: 'پارامترها را بررسی کنید'
})
} else console.log(e)
})
}
},
head() {
return {
title: this.title,
};
},
layout: "admin",
async asyncData({$axios, error}) {
try {
const yearBanner = await $axios.get('/api/public/yearBanner')
return {
yearBanner: yearBanner.data
}
} catch (e) {
if (e?.response?.status === 401) {
error({
status: 401,
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (e?.response?.status === 403) {
error({
status: 403,
message: e?.response?.data?.message,
});
}
if (e?.response?.status === 500) {
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات پیش آمده",
});
} else
error({
status: 404,
message: "اسلایدر مورد نظر پیدا نشد",
});
}
},
}
</script>
+875
View File
@@ -0,0 +1,875 @@
<template>
<div class="electionCandidate">
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="primary" class="mr-auto" :to="{ name: 'admin-elections',query: {page: 1} }">برگشت به
صفحه قبل
</CButton>
<CButton v-if="$route.params.details === 'new'" size="sm" color="success" class="mr-1" @click="post">افزودن
</CButton>
<CButton v-else size="sm" color="success" class="mr-1" @click="update">بروزرسانی</CButton>
</CustomSubHeader>
<CRow style="display : flex ; flex-direction: column">
<CRow>
<CCol lg="6">
<CCard>
<CCardBody>
<CRow>
<CCol sm="12">
<CInput
label="عنوان"
:class="validation.title ? 'err' : null"
:description="validation.title ? validation.title.msg : null"
v-model="election.title"
/>
</CCol>
<CCol sm="12">
<CTextarea
:class="validation.description ? 'err' : null"
label="توضیحات"
:description="validation.description ? validation.description.msg : null"
v-model="election.description"
/>
</CCol>
<el-divider></el-divider>
<CCol sm="12">
<h6>تاریخ شروع</h6>
<date-picker format="YYYY-MM-DD" display-format="jMMMM jD" v-model="election.startDate"></date-picker>
<p class="text-danger" v-if="validation.startDate">{{ validation.startDate.msg }}</p>
</CCol>
<CCol sm="12" class="mt-3">
<h6>تاریخ پایان</h6>
<date-picker format="YYYY-MM-DD" display-format="jMMMM jD" v-model="election.endDate"></date-picker>
<p class="text-danger" v-if="validation.endDate">{{ validation.endDate.msg }}</p>
</CCol>
</CRow>
</CCardBody>
</CCard>
</CCol>
<CCol lg="6">
<CCard>
<CCardBody>
<CCol sm="12">
<h6>{{ this.$route.params.details !== "new" ? "دسته بندی" : "انتخاب دسته بندی" }}</h6>
<el-select
filterable
clearable
style="width : 100%"
v-model="catId"
placeholder="انتخاب دسته بندی">
<el-option
v-for="item in categories"
v-if="availableCategory(item._id)"
:key="item._id"
:label="item.title"
:value="item._id"
>
<!-- <span>{{setTitle(item)}}</span> -->
</el-option>
</el-select>
<p style="margin-top : 5px !important ; color : red" class="form-err" v-if="validation.catId">
{{ validation.catId.msg }}</p>
</CCol>
<el-divider></el-divider>
<el-checkbox label="نمایش داده شود" v-model="election.publish"/>
</CCardBody>
</CCard>
</CCol>
<CCol sm="12" v-if="$route.params.details !== 'new'">
<CCard>
<CCardBody>
<CRow>
<CCol>
<div class="d-flex">
<h4 style="display: inline-block;">لیست کاندیداها</h4>
<el-button type="success" size="small" @click="detailsCandidate(false)" class="mr-auto">افزودن
</el-button>
</div>
<el-divider></el-divider>
<el-table
style="width: 100%;"
:data="election.candidates"
>
<el-table-column
type="index"
label="#"
>
</el-table-column>
<el-table-column
label="عکس"
>
<template slot-scope="scope">
<img :src="scope.row.profilePic" width="50px" alt="">
</template>
</el-table-column>
<el-table-column
label="نام"
>
<template slot-scope="scope">
{{ scope.row.firstName + ' ' + scope.row.lastName }}
</template>
</el-table-column>
<el-table-column
label="ویرایش"
width="120"
>
<template slot-scope="scope">
<CButton color="danger" variant="outline" :key="scope.row._id+1" @click="removeCandidate(scope.row._id)">
<i class="far fa-trash-alt"></i>
</CButton>
<CButton color="success" variant="outline" :key="scope.row._id"
@click="detailsCandidate(scope.row)">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
<p class="text-danger" v-if="validation.options">{{ validation.options.msg }}</p>
</CCol>
</CRow>
</CCardBody>
</CCard>
</CCol>
<CCol sm="12" v-if="$route.params.details !== 'new'">
<CCard>
<CCardBody>
<CRow>
<CCol lg="6">
<h4>لیست رای دهندگان</h4>
<el-divider></el-divider>
<el-table
style="width: 100%;"
:data="election.voters"
>
<el-table-column
type="index"
label="#"
>
</el-table-column>
<el-table-column
label="نام"
>
<template slot-scope="scope">
{{ scope.row.firstName + ' ' + scope.row.lastName }}
</template>
</el-table-column>
<el-table-column
prop="username"
label="نام کاربری"
>
</el-table-column>
<el-table-column
prop="password"
label="کلمه عبور"
>
</el-table-column>
<el-table-column
label="وضعیت رای"
>
<template slot-scope="scope">
<el-tag v-if="scope.row.voted" type="success">رای داده</el-tag>
<el-tag v-else type="danger">رای نداده</el-tag>
</template>
</el-table-column>
<el-table-column
label="ویرایش"
width="65"
>
<template slot-scope="scope">
<CButton color="danger" variant="outline" :key="scope.row._id+1" @click="removeVoter(scope.row._id)">
<i class="far fa-trash-alt"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCol>
<CCol lg="6">
<h4>افزودن رای دهنده</h4>
<el-divider></el-divider>
<CRow style="flex-direction: column;">
<CCol>
<CInput
label="نام"
:class="validation.firstName ? 'err' : null"
:description="validation.firstName ? validation.firstName.msg : null"
v-model="newVoter.firstName"
/>
</CCol>
<CCol>
<CInput
label="نام خانوادگی"
:class="validation.lastName ? 'err' : null"
:description="validation.lastName ? validation.lastName.msg : null"
v-model="newVoter.lastName"
/>
</CCol>
<CCol>
<CInput
label="نام کاربری"
:class="validation.username ? 'err' : null"
:description="validation.username ? validation.username.msg : null"
v-model="newVoter.username"
/>
</CCol>
<CCol>
<CInput
label="کد ملی"
:class="validation.nationalCode ? 'err' : null"
:description="validation.nationalCode ? validation.nationalCode.msg : null"
v-model="newVoter.nationalCode"
/>
</CCol>
<CCol>
<CInput
label="شماره موبایل"
:class="validation.mobileNumber ? 'err' : null"
:description="validation.mobileNumber ? validation.mobileNumber.msg : null"
v-model="newVoter.mobileNumber"
/>
</CCol>
<CCol>
<CInput
label="شغل"
:class="validation.job ? 'err' : null"
:description="validation.job ? validation.job.msg : null"
v-model="newVoter.job"
/>
</CCol>
<CCol>
<CButton color="success" variant="outline" @click="addVoter">افزودن</CButton>
</CCol>
</CRow>
</CCol>
</CRow>
</CCardBody>
</CCard>
</CCol>
<CCol sm="12" v-if="$route.params.details !== 'new'">
<CCard>
<CCardBody>
<h4>نتایج انتخابات</h4>
<el-divider></el-divider>
<div class="survey-item2" v-for="(item, index) in election.candidates" :key="item._id+2">
<h4>{{ item.firstName + ' ' + item.lastName }}</h4>
<el-progress :percentage="progress(item)" style="direction: rtl" color="#CC0000"></el-progress>
</div>
</CCardBody>
</CCard>
</CCol>
<!-------------------------- candidate modal --------------------------------------------->
<el-dialog title="اطلاعات کاندیدا" :visible.sync="showCandidate">
<CContainer style="border: solid 1px;padding: 25px;border-radius: 15px;">
<CRow style="flex-direction: column;">
<CCol>
<CInput
label="نام"
:class="validation.firstName ? 'err' : null"
:description="validation.firstName ? validation.firstName.msg : null"
v-model="candidateDetail.firstName"
/>
</CCol>
<CCol>
<CInput
label="نام خانوادگی"
:class="validation.lastName ? 'err' : null"
:description="validation.lastName ? validation.lastName.msg : null"
v-model="candidateDetail.lastName"
/>
</CCol>
<CCol>
<CInput
label="کد ملی"
:class="validation.nationalCode ? 'err' : null"
:description="validation.nationalCode ? validation.nationalCode.msg : null"
v-model="candidateDetail.nationalCode"
/>
</CCol>
<CCol>
<CTextarea
label="رزومه"
:class="validation.resume ? 'err' : null"
:description="validation.resume ? validation.resume.msg : null"
v-model="candidateDetail.resume"
/>
</CCol>
<CCol>
<span>تاریخ تولد</span>
<date-picker clearable format="YYYY-MM-DD" display-format="jMMMM jD"
v-model="candidateDetail.bornDate"></date-picker>
</CCol>
<CCol>
<h4>عکس</h4>
<el-divider/>
<CCol>
<img :src="candidateDetail.profilePic" style="width: 100%;max-width: 500px;" alt=""/>
</CCol>
<input type="file" ref="profilePic" @change="imagePreview"/>
<p style="margin-top: 5px !important;" class="form-err text-danger" v-if="validation.profilePic">
{{ validation.profilePic.msg }}</p>
<p class="mt-3 text-muted">
عکس 400*300 باشد. در غیر این صورت اتوماتیک بریده می شود.
</p>
</CCol>
<CButton color="success" variant="outline"
@click="candidateDetailType === 'add' ? addCandidate() : updateCandidate(candidateDetail._id)">{{ candidateDetailType === 'add' ? 'افزودن' : 'بروزرسانی' }}
</CButton>
</CRow>
</CContainer>
</el-dialog>
</CRow>
</CRow>
</div>
</template>
<script>
export default {
data() {
return {
election: null,
categories: null,
validation: {},
newOption: '',
showCandidate: false,
candidateDetail: {},
candidateDetailType: '',
newVoter: {
firstName: '',
lastName: '',
username: '',
nationalCode: '',
mobileNumber: '',
jon: '',
}
}
},
computed: {
title() {
return this.$route.params.details === "new" ? "افزودن انتخابات جدید" : "مشاهده انتخابات"
},
catId: {
get() {
if (this.$route.params.details === 'new') {
return this.election.catId
} else {
return this.election.catId._id
}
},
set(value) {
if (this.$route.params.details === 'new') {
this.election.catId = value
} else {
this.election.catId._id = value
}
}
}
},
methods: {
progress(answerItem) {
const availableOptions = this.election.candidates.map(item => item._id)
let filteredAnswers = this.election.votes.filter(item => availableOptions.includes(item.candidate))
let num = filteredAnswers.filter(item => item.candidate === answerItem._id).length
return Number(((num * 100 / filteredAnswers.length) || 0).toFixed(0))
},
imagePreview(e) {
this.candidateDetail.profilePic = URL.createObjectURL(e.target.files[0]);
},
detailsCandidate(candidate) {
this.showCandidate = !this.showCandidate;
if (candidate) {
this.candidateDetailType = 'update';
this.candidateDetail = candidate;
} else {
this.candidateDetailType = 'add';
this.candidateDetail = {
firstName: '',
lastName: '',
bornDate: '',
education: '',
nationalCode: '',
resume: '',
profilePic: '',
}
}
},
availableCategory(id) {
return this.$auth.user.permissions.includes('superAdmin') || this.$auth.user.specialPermissions.includes(id)
},
post() {
this.validation = {}
this.$axios
.post(`/api/admin/election`, this.election)
.then((response) => {
this.$message({
type: "success",
message: "نظرسنجی با موفقیت ایجاد شد."
})
this.$router.push({name: 'admin-elections-details', params: {details: response.data._id}})
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید."
})
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message
})
}
if (err.response.status === 500) {
return this.$message({
type: "error",
message: "مشکلی در ارسال درخواست پیش آمده"
})
}
if (err.response.status === 422) {
this.validation = err.response.data.validation
this.$message({
type: 'warning',
message: 'پارامترها رو بررسی کنید'
})
} else console.log(err.response.data)
})
},
update() {
this.validation = {}
this.$axios.put(`/api/admin/election/${this.election._id}`, {...this.election, catId: this.catId})
.then((response) => {
this.$message({
type: "success",
message: "اطلاعات بروزرسانی شد."
})
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید."
})
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message
})
}
if (err.response.status === 500) {
return this.$message({
type: "error",
message: "مشکلی در ارسال درخواست پیش آمده"
})
}
if (err.response.status === 422) {
this.validation = err.response.data.validation
this.$message({
type: 'warning',
message: 'پارامترها رو بررسی کنید'
})
} else console.log(err.response.data)
});
},
addCandidate() {
this.validation = {}
const data = new FormData();
data.append("firstName", this.candidateDetail.firstName);
data.append("lastName", this.candidateDetail.lastName);
data.append("bornDate", this.candidateDetail.bornDate);
data.append("education", this.candidateDetail.education);
data.append("nationalCode", this.candidateDetail.nationalCode);
data.append("resume", this.candidateDetail.resume);
data.append("profilePic", this.$refs.profilePic.files[0]);
this.$axios.post(`/api/admin/election/candidate/${this.$route.params.details}`, data)
.then((response) => {
this.showCandidate = false;
this.$message({
type: "success",
message: "کاندیدا با موفقیت ایجاد شد"
})
this.$nuxt.refresh();
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید."
})
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message
})
}
if (err.response.status === 500) {
return this.$message({
type: "error",
message: "مشکلی در ارسال درخواست پیش آمده"
})
}
if (err.response.status === 422) {
this.validation = err.response.data.validation
this.$message({
type: 'warning',
message: 'پارامترها رو بررسی کنید'
})
} else console.log(err.response.data)
})
},
updateCandidate(id) {
const data = new FormData();
data.append("firstName", this.candidateDetail.firstName);
data.append("lastName", this.candidateDetail.lastName);
data.append("bornDate", this.candidateDetail.bornDate);
data.append("education", this.candidateDetail.education);
data.append("nationalCode", this.candidateDetail.nationalCode);
data.append("resume", this.candidateDetail.resume);
data.append("candidateId", id);
if (this.$refs.profilePic.files[0]) data.append("profilePic", this.$refs.profilePic.files[0]);
this.validation = {}
this.$axios.put(`/api/admin/election/candidate/${this.$route.params.details}`, data)
.then((response) => {
this.showCandidate = false;
this.$message({
type: "success",
message: "کاندیدا با موفقیت بروزرسانی شد"
})
this.$nuxt.refresh();
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید."
})
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message
})
}
if (err.response.status === 500) {
return this.$message({
type: "error",
message: "مشکلی در ارسال درخواست پیش آمده"
})
}
if (err.response.status === 422) {
this.validation = err.response.data.validation
this.$message({
type: 'warning',
message: 'پارامترها رو بررسی کنید'
})
} else console.log(err.response.data)
})
},
removeCandidate(id) {
this.$confirm("کاندیدا حذف شود؟", "اخطار", {
confirmButtonText: "بله",
cancelButtonText: "لغو",
type: "warning"
})
.then(() => {
this.$axios.delete(`/api/admin/election/candidate/${this.$route.params.details}/${id}`)
.then((response) => {
this.$message({
type: "success",
message: "کاندیدا با موفقیت حذف شد."
})
this.$nuxt.refresh()
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید."
})
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message
})
}
if (err.response.status === 500) {
return this.$message({
type: "error",
message: "مشکلی در ارسال درخواست پیش آمده"
})
}
if (err.response.status === 422) {
this.validation = err.response.data.validation
this.$message({
type: 'warning',
message: 'پارامترها رو بررسی کنید'
})
} else console.log(err.response.data)
})
})
.catch(() => {
this.$message({
type: "warning",
message: "عملیات لغو شد"
})
})
},
addVoter() {
this.validation = {}
this.$axios.post(`/api/admin/election/voter/${this.$route.params.details}`, this.newVoter)
.then((response) => {
this.$message({
type: "success",
message: "رای دهنده با موفقیت ایجاد شد"
})
this.$nuxt.refresh();
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید."
})
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message
})
}
if (err.response.status === 500) {
return this.$message({
type: "error",
message: "مشکلی در ارسال درخواست پیش آمده"
})
}
if (err.response.status === 422) {
this.validation = err.response.data.validation
this.$message({
type: 'warning',
message: 'پارامترها رو بررسی کنید'
})
} else console.log(err.response.data)
})
},
removeVoter(id) {
this.$confirm("رای دهنده حذف شود؟", "اخطار", {
confirmButtonText: "بله",
cancelButtonText: "لغو",
type: "warning"
})
.then(() => {
this.$axios.delete(`/api/admin/election/voter/${this.$route.params.details}/${id}`)
.then((response) => {
this.$message({
type: "success",
message: "رای دهنده با موفقیت حذف شد."
})
this.election.voters = this.election.voters.filter(item => item._id !== id)
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید."
})
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message
})
}
if (err.response.status === 500) {
return this.$message({
type: "error",
message: "مشکلی در ارسال درخواست پیش آمده"
})
}
if (err.response.status === 422) {
this.validation = err.response.data.validation
this.$message({
type: 'warning',
message: 'پارامترها رو بررسی کنید'
})
} else console.log(err.response.data)
})
})
.catch(() => {
this.$message({
type: "warning",
message: "عملیات لغو شد"
})
})
},
},
head() {
return {
title: this.title,
}
},
layout: "admin",
async asyncData({$axios, params, error}) {
try {
const categories = await $axios.get('/api/admin/category/getParent')
if (params.details !== 'new') {
const election = await $axios.get(`/api/admin/election/${params.details}`)
return {
categories: categories.data,
election: election.data
}
} else {
return {
categories: categories.data,
election: {
title: '',
description: '',
catId: '',
startDate: '',
endDate: '',
publish: true,
}
}
}
} catch (e) {
if (e?.response?.status === 401) error({status: 401, message: "لطفا دوباره وارد سیستم شوید."})
if (e?.response?.status === 403) error({status: 403, message: e?.response?.data?.message})
if (e?.response?.status === 500) error({status: 500, message: "مشکلی در گرفتن اطلاعات پیش آمده"})
else error({status: 404, message: "پرونده خبری مورد نظر پیدا نشد"})
}
},
}
</script>
<style lang="scss">
.electionCandidate .el-dialog {
@media (max-width: 768px) {
width: 90%;
}
}
</style>
<style lang="scss">
.survey-item2 {
padding: 20px 0;
.el-radio-group {
direction: ltr;
.el-radio__input.is-checked .el-radio__inner {
background: red;
border-color: red;
}
.el-radio__input.is-checked + .el-radio__label {
color: red;
}
.el-radio__label {
&:hover {
color: red;
}
}
.el-radio__inner {
border: 1px solid #666666;
}
.el-radio__inner:hover {
border-color: red;
}
}
.comment-btn {
display: flex;
justify-content: flex-end;
button {
&:disabled {
border-color: #666666;
background-color: #666666;
color: white;
border-radius: 5px;
}
}
}
.el-checkbox-group {
direction: ltr;
text-align: right;
.el-checkbox__inner {
border: 1px solid #666666;
&:hover {
border-color: red;
}
}
}
.el-checkbox__input.is-checked .el-checkbox__inner, .el-checkbox__input.is-indeterminate .el-checkbox__inner {
background-color: red;
border-color: red;
}
.el-checkbox__label {
&:hover {
color: red;
}
}
.el-checkbox__input.is-checked + .el-checkbox__label {
color: red;
}
.el-progress {
font-family: 'sansNum', sans-serif;
.el-progress-bar__inner {
right: 0;
}
.el-progress__text {
margin-right: 10px;
}
}
}
</style>
+293
View File
@@ -0,0 +1,293 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="success" :to="{ name: 'admin-elections-details', params: { details: 'new' } }" class="mr-auto">افزودن</CButton>
</CustomSubHeader>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-filter"></i>
<span style="color:#000">فیلتر</span>
</slot>
</CCardHeader>
<CCardBody>
<CRow>
<CCol md="6">
<CRow style="flex-direction : column;">
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>عنوان</span>
</CCol>
<CCol col="md-9">
<el-input style="width : 100%" placeholder="" v-model="search.term"></el-input>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>تاریخ</span>
</CCol>
<CCol col="md-9">
<date-picker range clearable format="YYYY-MM-DD" display-format="jMMMM jD" v-model="search.date"></date-picker>
</CCol>
</CRow>
</CCol>
</CRow>
</CCol>
<CCol md="6">
<CRow style="flex-direction : column;">
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>وضعیت نمایش</span>
</CCol>
<CCol col="md-9">
<el-select v-model="search.publish" clearable style="width : 100%" placeholder="">
<el-option :key="true" label="نمایش داده شود" :value="true">
</el-option>
<el-option :key="false" label="نمایش داده نشود" :value="false">
</el-option>
</el-select>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>دسته بندی</span>
</CCol>
<CCol col="md-9">
<el-select filterable clearable style="width : 100%" v-model="search.catId"
placeholder="انتخاب دسته بندی">
<el-option v-for="item in parents" :key="item._id" :label="item.title" :value="item._id"/>
</el-select>
</CCol>
</CRow>
</CCol>
</CRow>
</CCol>
</CRow>
<CRow>
<el-button :loading="loading" @click="handleSearch" size="small" style="width: auto;margin: 25px auto auto auto;" type="primary" icon="el-icon-search">جست و جو</el-button>
</CRow>
</CCardBody>
</CCard>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>{{ list_title }}</span>
</slot>
<slot></slot>
</CCardHeader>
<CCardBody>
<el-table
v-loading="loading"
:data="elections.docs"
:default-sort="{ prop: 'date', order: 'descending' }"
style="width: 100%"
>
<el-table-column
type="index"
label="#"
>
</el-table-column>
<el-table-column label="عنوان">
<template slot-scope="scope">
<span class="title">
<el-popover placement="top-end" trigger="hover" :content="scope.row.title">
<i v-if="scope.row.title.length > 25" class="el-icon-info" slot="reference"></i>
</el-popover>
{{ scope.row.title }}
</span>
</template>
</el-table-column>
<el-table-column
prop="catId.title"
label="دسته بندی"
width="">
</el-table-column>
<el-table-column
label="تاریخ شروع"
width=""
>
<template slot-scope="scope">
<span>{{ jDate(scope.row.startDate) }}</span>
</template>
</el-table-column>
<el-table-column
label="تاریخ پایان"
width=""
>
<template slot-scope="scope">
<span>{{ jDate(scope.row.endDate) }}</span>
</template>
</el-table-column>
<el-table-column label="ویرایش" width="110" align="center">
<template slot-scope="scope">
<CButton color="danger" variant="outline" :key="scope.row._id + Math.random()" @click="deletePoll(scope.row._id)">
<i class="far fa-trash-alt"></i>
</CButton>
<CButton color="success" variant="outline" :key="scope.row._id" :to="{ name: 'admin-elections-details',params: { details: scope.row._id } }">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
<CCard class="col" v-if="elections.totalDocs>5">
<CRow alignHorizontal="center" style="padding : 10px">
<el-pagination :hide-on-single-page="true" layout="prev, pager, next" :page-size="elections.limit"
@current-change="handleCurrentChange" :current-page.sync="elections.page" :total="elections.totalDocs">
</el-pagination>
</CRow>
</CCard>
</div>
</template>
<script>
import moment from "moment-jalaali"
export default {
data() {
return {
title: "لیست انتخابات",
list_title: "لیست",
elections: null,
search: {},
parent: null,
loading: false
};
},
computed: {
pageQuery() {
return this.$route.query.page;
}
},
watch: {
pageQuery(newPage, oldPage) {
this.$nuxt.refresh()
}
},
methods: {
jDate(date) {
return moment(date).format("jYYYY/jMM/jDD")
},
deletePoll(id) {
this.$confirm("انتخابات حذف شود؟", "اخطار", {
confirmButtonText: "بله",
cancelButtonText: "لغو",
type: "warning"
})
.then(async () => {
this.$axios
.delete(`/api/admin/election/${id}`)
.then((res) => {
this.$message({
type: "success",
message: "انتخابات با موفقیت حذف شد"
})
this.elections.docs = this.elections.docs.filter(item => item._id !== id)
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید."
})
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message
})
}
if (err.response.status === 422) {
return this.$message({
type: "error",
message: err.response.data.message
})
}
console.log(err.response.data)
})
})
.catch(() => {
this.$message({
type: "warning",
message: "عملیات لغو شد"
})
})
},
handleCurrentChange(page) {
this.handleSearch(page)
},
handleSearch(page) {
this.loading = true;
const data = {
term: this.search.term,
catId: this.search.catId,
showInHome: this.search.showInHome
}
this.$axios.post(`/api/admin/election/search?page=${page}`, data, this.axiosConfig)
.then((result) => {
this.elections = result.data;
this.loading = false;
})
.catch(err => {
this.loading = false;
if (err.response.status === 401) {
return this.$message({
type: 'error',
message: 'لطفا دوباره وارد سیستم شوید.'
})
}
if (err.response.status === 422) this.validation = err.response.data.validation
else console.log(err.response.data)
})
}
},
head() {
return {
title: this.title
}
},
layout: "admin",
async asyncData({$axios, query, error}) {
try {
const requests = [
$axios.get(`/api/admin/election?page=${query.page}`),
$axios.get("/api/admin/category/getParent")
]
const fetch = await Promise.all(requests)
let [elections, parents] = fetch
return {
elections: elections.data,
parents: parents.data
}
} catch (e) {
if (e?.response?.status === 401) error({status: 401, message: 'شما اجازه دسترسی به این صفحه را ندارید'})
else error({status: 500, message: "مشکلی در گرفتن اطلاعات بوجود آمده است"})
}
}
}
</script>
+792
View File
@@ -0,0 +1,792 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="primary" class="mr-auto" :to="{ name: 'admin-gallery' }">برگشت به صفحه قبل</CButton>
<CButton v-if="$route.params.details === 'new'" size="sm" color="success" class="mr-1" @click="post">افزودن
</CButton>
<CButton v-else size="sm" color="success" class="mr-1" @click="update">بروزرسانی</CButton>
</CustomSubHeader>
<CRow style="flex-direction: column;">
<CCol>
<CCard>
<CCardBody>
<CRow>
<CCol lg="6">
<h6>
قسمت انتخابی
<i v-c-tooltip="
'شما باید تعیین کنید که این رسانه برای کدام قسمت پرتال می باشد'
" class="fas fa-question-circle"></i>
</h6>
<el-select :disabled="$auth.user.portals.length === 1" v-model="gallery.modelType"
@change="changePortalVal"
placeholder="انتخاب کنید" style="width: 100%;">
<el-option v-for="item in portals" :key="item.value" :label="item.name" :value="item.value">
</el-option>
</el-select>
<p style="margin-top : 5px !important ; color : red" class="form-err" v-if="validation.modelType">
{{ validation.modelType.msg }}
</p>
<template v-if="gallery.modelType">
<el-divider></el-divider>
<h6>
{{
this.$route.params.details !== "new"
? "دسته بندی"
: "انتخاب دسته بندی"
}}
</h6>
<el-select
filterable
clearable
style="width : 100%"
v-model="catId"
placeholder="انتخاب دسته بندی">
<el-option
v-for="item in filterParent"
v-if="availableCategory(item._id)"
:key="item._id"
:label="item.title"
:value="item._id"
>
<!-- <span>{{setTitle(item)}}</span> -->
</el-option>
</el-select>
<p style="margin-top : 5px !important ; color : red" class="form-err" v-if="validation.catId">
{{ validation.catId.msg }}
</p>
</template>
<el-divider/> <!--- details --->
<CTextarea :class="validation.summaryTitle ? 'err' : null" label="رو تیتر"
:description="validation.summaryTitle ? validation.summaryTitle.msg : null"
v-model="gallery.summaryTitle"/>
<CTextarea
:class="validation.title ? 'err' : null"
label="تیتر"
:description="
validation.title
? validation.title.msg
: null
"
v-model="gallery.title"
/>
<CTextarea
:class="validation.leadTitle ? 'err' : null"
label="لید"
:description="validation.leadTitle? validation.leadTitle.msg: null "
v-model="gallery.leadTitle"
rows="3"
/>
<CTextarea
:class="validation.metaTagDesc ? 'err' : null"
label="توضیحات برای موتورهای جست و جو"
placeholder="در صورتی که این کادر را خالی بگذارید از متن لید استفاده خواهد شد."
:description="validation.metaTagDesc? validation.metaTagDesc.msg: null"
v-model="gallery.metaTagDesc"
rows="3"
/>
<p>کلمات کلیدی</p>
<div>
<el-input
class="input-new-tag mb-3"
v-if="inputVisible"
v-model="inputValue"
ref="saveTagInput"
size="small"
@keyup.enter.native="handleInputConfirm"
@blur="handleInputConfirm"
>
</el-input>
<el-button
v-else
class="button-new-tag mb-3"
size="small"
@click="showInput"
>کلمه جدید
</el-button
>
</div>
<div class="mb-3">
<el-tag
class="ml-1"
:key="tag"
v-for="tag in gallery.keywords"
closable
:disable-transitions="false"
@close="handleClose(tag)"
>
{{ tag }}
</el-tag>
</div>
</CCol>
<!-- <CCol lg="6">-->
<!-- <h6>-->
<!-- قسمت انتخابی-->
<!-- <i v-c-tooltip="-->
<!-- 'شما باید تعیین کنید که این رسانه برای کدام قسمت پرتال می باشد'-->
<!-- " class="fas fa-question-circle"></i>-->
<!-- </h6>-->
<!-- <el-select :disabled="$auth.user.portals.length === 1" v-model="gallery.modelType"-->
<!-- @change="changePortalVal"-->
<!-- placeholder="انتخاب کنید" style="width: 100%;">-->
<!-- <el-option v-for="item in portals" :key="item.value" :label="item.name" :value="item.value">-->
<!-- </el-option>-->
<!-- </el-select>-->
<!-- <p style="margin-top : 5px !important ; color : red" class="form-err" v-if="validation.modelType">-->
<!-- {{ validation.modelType.msg }}-->
<!-- </p>-->
<!-- <template v-if="gallery.modelType">-->
<!-- <el-divider></el-divider>-->
<!-- <h6>-->
<!-- {{-->
<!-- this.$route.params.details !== "new"-->
<!-- ? "دسته بندی"-->
<!-- : "انتخاب دسته بندی"-->
<!-- }}-->
<!-- </h6>-->
<!-- <el-select-->
<!-- filterable-->
<!-- clearable-->
<!-- style="width : 100%"-->
<!-- v-model="catId"-->
<!-- placeholder="انتخاب دسته بندی">-->
<!-- <el-option-->
<!-- v-for="item in filterParent"-->
<!-- v-if="availableCategory(item._id)"-->
<!-- :key="item._id"-->
<!-- :label="item.title"-->
<!-- :value="item._id"-->
<!-- >-->
<!-- &lt;!&ndash; <span>{{setTitle(item)}}</span> &ndash;&gt;-->
<!-- </el-option>-->
<!-- </el-select>-->
<!-- <p style="margin-top : 5px !important ; color : red" class="form-err" v-if="validation.catId">-->
<!-- {{ validation.catId.msg }}-->
<!-- </p>-->
<!-- </template>-->
<!-- <el-divider/> &lt;!&ndash;- details -&ndash;&gt;-->
<!-- <CTextarea :class="validation.summaryTitle ? 'err' : null" label="رو تیتر"-->
<!-- :description="validation.summaryTitle ? validation.summaryTitle.msg : null"-->
<!-- v-model="gallery.summaryTitle"/>-->
<!-- <CTextarea-->
<!-- :class="validation.title ? 'err' : null"-->
<!-- label="تیتر"-->
<!-- :description="-->
<!-- validation.title-->
<!-- ? validation.title.msg-->
<!-- : null-->
<!-- "-->
<!-- v-model="gallery.title"-->
<!-- />-->
<!-- <CTextarea-->
<!-- :class="validation.leadTitle ? 'err' : null"-->
<!-- label="لید"-->
<!-- :description="validation.leadTitle? validation.leadTitle.msg: null "-->
<!-- v-model="gallery.leadTitle"-->
<!-- rows="3"-->
<!-- />-->
<!-- <CTextarea-->
<!-- :class="validation.metaTagDesc ? 'err' : null"-->
<!-- label="توضیحات برای موتورهای جست و جو"-->
<!-- placeholder="در صورتی که این کادر را خالی بگذارید از متن لید استفاده خواهد شد."-->
<!-- :description="validation.metaTagDesc? validation.metaTagDesc.msg: null"-->
<!-- v-model="gallery.metaTagDesc"-->
<!-- rows="3"-->
<!-- />-->
<!-- <p>کلمات کلیدی</p>-->
<!-- <div>-->
<!-- <el-input-->
<!-- class="input-new-tag mb-3"-->
<!-- v-if="inputVisible"-->
<!-- v-model="inputValue"-->
<!-- ref="saveTagInput"-->
<!-- size="small"-->
<!-- @keyup.enter.native="handleInputConfirm"-->
<!-- @blur="handleInputConfirm"-->
<!-- >-->
<!-- </el-input>-->
<!-- <el-button-->
<!-- v-else-->
<!-- class="button-new-tag mb-3"-->
<!-- size="small"-->
<!-- @click="showInput"-->
<!-- >کلمه جدید-->
<!-- </el-button-->
<!-- >-->
<!-- </div>-->
<!-- <div class="mb-3">-->
<!-- <el-tag-->
<!-- class="ml-1"-->
<!-- :key="tag"-->
<!-- v-for="tag in gallery.keywords"-->
<!-- closable-->
<!-- :disable-transitions="false"-->
<!-- @close="handleClose(tag)"-->
<!-- >-->
<!-- {{ tag }}-->
<!-- </el-tag>-->
<!-- </div>-->
<!-- </CCol>-->
<CCol lg="6">
<h6>
نوع رسانه
<i v-c-tooltip="
'شما باید تعیین کنید که این رسانه از چه نوعی می باشد'
" class="fas fa-question-circle"></i>
</h6>
<el-select @change="changeGalleryType" v-model="gallery.galleryType" placeholder="انتخاب کنید"
style="width: 100%;">
<el-option v-for="item in selectType" :key="item.value" :label="item.label" :value="item.value">
</el-option>
</el-select>
<p style="margin-top : 5px !important ; color : red" class="form-err" v-if="validation.galleryType">
{{ validation.galleryType.msg }}
</p>
<template v-if="$route.params.details !== 'new'">
<el-divider/>
<h6>
تغییر زمان ثبت خبر
</h6>
<date-picker clearable input-format="YYYY-MM-DD HH:mm" format="YYYY-MM-DD HH:mm"
display-format="jYYYY/jMM/jDD HH:mm"
v-model="gallery.customDate" type="datetime"/>
<p
style="margin-top : 5px !important ; color : red"
class="form-err"
v-if="validation.customDate"
>
{{ validation.customDate.msg }}
</p>
</template>
<!-- <el-divider/>-->
<!-- <h6>-->
<!-- انتخاب موضوع پرونده خبری-->
<!-- <i-->
<!-- v-c-tooltip="-->
<!-- 'شما می توانید در صورت تمایل این خبر را در یکی از موضوعات پرونده های خبری قرار دهید'-->
<!-- "-->
<!-- class="fas fa-question-circle"-->
<!-- ></i>-->
<!-- </h6>-->
<!-- <el-select-->
<!-- v-model="gallery.newsFileId"-->
<!-- placeholder="انتخاب کنید"-->
<!-- style="width: 100%;"-->
<!-- filterable-->
<!-- clearable-->
<!-- >-->
<!-- <el-option-->
<!-- v-for="item in filteredSetNewsFile"-->
<!-- :key="item._id"-->
<!-- :label="item.title"-->
<!-- :value="item._id"-->
<!-- >-->
<!-- </el-option>-->
<!-- </el-select>-->
<!-- <p-->
<!-- style="margin-top : 5px !important ; color : red"-->
<!-- class="form-err"-->
<!-- v-if="validation.newsFileId"-->
<!-- >-->
<!-- {{ validation.newsFileId.msg }}-->
<!-- </p>-->
<el-divider/>
<CCol sm="12">
<el-checkbox v-model="gallery.favorite" label="نمایش در قسمت برگزیده ها"/>
</CCol>
<CCol sm="12">
<el-checkbox v-model="gallery.special" label="نمایش در بالای صفحه"/>
</CCol>
<CCol sm="12">
<el-checkbox v-model="gallery.publish" label="انتشار رسانه"/>
</CCol>
<CCol sm="12">
<el-checkbox v-if="gallery.galleryType === 'video'" v-model="gallery.isEmbedded"
label="استفاده از فیلمی بارگزاری شده در آپارات"/>
</CCol>
<CCol sm="12">
<el-checkbox v-model="gallery.showInHome" label="نمایش رسانه در صفحه اصلی"/>
</CCol>
</CCol>
</CRow>
<!-- <CRow>-->
<!-- <CCol lg="6">-->
<!-- -->
<!-- </CCol>-->
<!-- <CCol lg="6">-->
<!-- <el-divider/>-->
<!-- -->
<!-- </CCol>-->
<!-- </CRow>-->
</CCardBody>
</CCard>
</CCol>
<template v-if="$route.params.details !== 'new'">
<CCol>
<CCard>
<CCardBody>
<CRow style="text-align: center;">
<h6 class="mb-3 mr-1">کاور رسانه</h6>
<el-upload :show-file-list="false" action="/api/admin/gallery/uploadCover" class="avatar-uploader"
:headers="{'Authorization' : `Bearer ${$auth.user.token}`}"
:data="{galleryId : gallery._id}"
:on-preview="handlePictureCardPreview" :on-remove="handleRemove"
:on-success="fileUploadSuccess"
:on-progress="handleProcess" :on-error="fileUploadError">
<img v-if="gallery.cover" :src="gallery.thumbCover" class="avatar" alt="">
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</CRow>
</CCardBody>
</CCard>
</CCol>
</template>
<template v-if="$route.params.details !== 'new' && showSectionUpload">
<CCol>
<CCard>
<CCardBody>
<CRow style="text-align: center;" v-if="!gallery.isEmbedded">
<h6 class="mb-3 mr-1">
{{ this.gallery.galleryType === 'video' ? 'بارگزاری فیلم' : 'بارگزاری عکس' }}</h6>
<el-upload :show-file-list="false" action="/api/admin/gallery/uploadFile" class="upload-demo" drag
:headers="{'Authorization' : `Bearer ${$auth.user.token}`}"
:data="{galleryId : gallery._id , fileType : gallery.galleryType}"
:multiple="this.gallery.galleryType!=='video'"
:on-preview="handlePictureCardPreview" :on-remove="handleRemove"
:on-success="fileUploadSuccess" :on-progress="handleProcess" :on-error="fileUploadError">
<i class="el-icon-upload"></i>
<div class="el-upload__text">یک فایل را بکشید یا <em>برای آپلود کلیک کنید</em></div>
<div class="el-upload__tip" slot="tip">
{{
this.gallery.galleryType === 'video' ? 'فیلم نباید بیشتر از 20 مگابایت باشد و دارای فرمت mp4 باشد' : 'عکس 600*300 باشد. در غیر این صورت اتوماتیک بریده می شود'
}}
</div>
</el-upload>
</CRow>
<CRow style="text-align: center;" v-else>
<CTextarea
:class="validation.embeddedCode ? 'err' : null"
label="کد امبدد از سایت آپارات را اینجا وارد کنید (کدآی فریم)"
placeholder="کد آی فریم را جای گزاری کنید"
:description="validation.embeddedCode ? validation.embeddedCode.msg : null"
v-model="gallery.embeddedCode"
rows="10"
/>
</CRow>
<el-dialog :visible.sync="dialogVisible">
<img width="100%" :src="dialogImageUrl" alt="">
</el-dialog>
<template v-if="gallery.embeddedCode">
<div v-html="gallery.embeddedCode"></div>
</template>
<template v-if="gallery.video && !gallery.isEmbedded">
<el-divider/>
<video class="mt-3" :poster="gallery.cover" width="100%" height="400" muted controls
:src="gallery.video">
</video>
</template>
<template v-else>
<el-divider/>
<template v-if="gallery.galleryType === 'image'">
<ul class="el-upload-list el-upload-list--picture-card">
<li v-for="(image , index) in gallery.thumbImages" :key="index"
class="el-upload-list__item is-success"><img
:src="image" :alt="image.split('/')[4]"
class="el-upload-list__item-thumbnail"><a class="el-upload-list__item-name"><i
class="el-icon-document"></i>{{ image.split('/')[4] }}
</a><label class="el-upload-list__item-status-label"><i
class="el-icon-upload-success el-icon-check"></i></label><i class="el-icon-close"></i>
<span class="el-upload-list__item-actions"><span class="el-upload-list__item-preview"
@click="handlePictureCardPreview(gallery.images[index])"><i
class="el-icon-zoom-in"></i></span><span class="el-upload-list__item-delete"
@click="handleRemove(gallery.images[index])"><i
class="el-icon-delete"></i></span></span></li>
</ul>
</template>
<template v-else>
<img width="100%" :src="gallery.graphic" alt="" class="">
</template>
</template>
<p style="color : red" class="form-err mt-2" v-if="validation.file">
{{ validation.file.msg }}
</p>
</CCardBody>
</CCard>
</CCol>
</template>
</CRow>
</div>
</template>
<script>
import axiosUploadProcess from "@/mixins/axiosUploadProcess";
export default {
data() {
return {
playsinline: true,
fileList: [],
selectType: [
{
label: "عکس",
value: "image",
},
{
label: "گرافیک",
value: "graphic",
},
{
label: "فیلم",
value: "video",
}
],
dialogImageUrl: '',
dialogVisible: false,
disabled: false,
gallery: null,
validation: {},
editorConfig: {
language: "en",
extraPlugins: ["bidi", "justify"],
},
filterParent: null,
portals: null,
newsFile: null,
showSectionUpload: false,
checkGalleryType: null,
loading: false,
inputVisible: false,
inputValue: ''
};
},
mixins: [axiosUploadProcess],
computed: {
title() {
return this.$route.params.details === "new" ? "افزودن رسانه جدید" : "مشاهده جزئیات رسانه"
},
catId: {
get() {
if (this.$route.params.details === 'new') {
return this.gallery.catId
} else {
return this.gallery.catId._id
}
},
set(value) {
if (this.$route.params.details === 'new') {
this.gallery.catId = value
} else {
this.gallery.catId._id = value
}
}
},
filteredSetNewsFile() {
return this.newsFile.filter(item => item.modelType === this.gallery.modelType && (this.$route.params.details === 'new' ? item.catId === this.gallery.catId : item.catId === this.gallery.catId._id))
}
},
methods: {
handleClose(tag) {
this.gallery.keywords.splice(this.gallery.keywords.indexOf(tag), 1);
},
showInput() {
this.inputVisible = true;
this.$nextTick((_) => {
this.$refs.saveTagInput.$refs.input.focus();
});
},
changePortalVal(value) {
this.catId = null;
if (this.$auth.user.specialPermissions.length) {
this.filterParent = this.parents.filter(
(item) => item.modelType === value
).filter((item) => {
return this.$auth.user.specialPermissions.includes(item._id)
});
} else {
this.filterParent = this.parents.filter(
(item) => item.modelType === value
);
}
},
handleInputConfirm() {
let inputValue = this.inputValue;
if (inputValue) {
this.gallery.keywords.push(inputValue);
}
this.inputVisible = false;
this.inputValue = "";
},
fileUploadSuccess(res, file, fileList) {
this.loading = false;
this.$nuxt.refresh();
},
handleProcess(err, file, fileList) {
this.loading = true;
},
fileUploadError(err, file, fileList) {
this.validation = JSON.parse(err.message).validation;
},
changeGalleryType(value) {
this.showSectionUpload = value === this.checkGalleryType;
},
handleRemove(file) {
this.loading = true;
this.validation = {};
const data = new FormData();
data.append("galleryId", this.gallery._id);
data.append("name", file.split('/')[4]);
this.$axios
.post(`/api/admin/gallery/deleteFile`, data, this.axiosConfig)
.then((response) => {
this.loading = false;
this.$message({
type: "success",
message: "فایل با موفقیت حذف شد",
});
this.$nuxt.refresh();
})
.catch((err) => {
this.loading = false;
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
if (err.response.status === 500) {
return this.$message({
type: "error",
message: "مشکلی در ارسال درخواست پیش آمده",
});
}
if (err.response.status === 422)
this.validation = err.response.data.validation;
else console.log(err.response.data);
});
},
handlePictureCardPreview(file) {
this.dialogImageUrl = file;
this.dialogVisible = true;
},
imagePreview(e) {
this.gallery.cover = URL.createObjectURL(e.target.files[0]);
},
availableCategory(id) {
return this.$auth.user.permissions.includes('superAdmin') || this.$auth.user.specialPermissions.includes(id)
},
post() {
this.validation = {};
const data = new FormData();
data.append("title", this.gallery?.title?.trim());
data.append("summaryTitle", this.gallery?.summaryTitle?.trim());
data.append("leadTitle", this.gallery.leadTitle);
data.append("isEmbedded", this.gallery.isEmbedded);
data.append("catId", this.catId);
data.append("priority", this.gallery.priority);
data.append("showInHome", this.gallery.showInHome);
data.append("publish", this.gallery.publish);
data.append("special", this.gallery.special);
data.append("galleryType", this.gallery.galleryType);
data.append("modelType", this.gallery.modelType);
data.append("favorite", this.gallery.favorite);
data.append("keywords", JSON.stringify(this.gallery.keywords));
data.append("metaTagDesc", this.gallery?.metaTagDesc || this.gallery?.leadTitle);
if (this.gallery.newsFileId) {
data.append("newsFileId", this.gallery.newsFileId);
}
this.$axios
.post(`/api/admin/gallery`, data, this.axiosConfig)
.then((response) => {
this.$message({
type: "success",
message: "رسانه با موفقیت ایجاد شد.",
});
this.$router.push({
name: "admin-gallery-details",
params: {
details: `${response.data._id}`
},
});
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
if (err.response.status === 500) {
return this.$message({
type: "error",
message: "مشکلی در ارسال درخواست پیش آمده",
});
}
if (err.response.status === 422)
this.validation = err.response.data.validation;
else console.log(err.response.data);
});
},
update() {
this.validation = {};
const data = new FormData();
data.append("title", this.gallery?.title?.trim());
data.append("summaryTitle", this.gallery?.summaryTitle?.trim());
data.append("leadTitle", this.gallery?.leadTitle?.trim());
data.append("catId", this.catId);
data.append("isEmbedded", this.gallery.isEmbedded);
if (this.gallery.embeddedCode) data.append("embeddedCode", this.gallery.embeddedCode);
data.append("priority", this.gallery.priority);
data.append("showInHome", this.gallery.showInHome);
data.append("publish", this.gallery.publish);
data.append("special", this.gallery.special);
data.append("galleryType", this.gallery.galleryType);
data.append("modelType", this.gallery.modelType);
data.append("favorite", this.gallery.favorite);
data.append("keywords", JSON.stringify(this.gallery.keywords));
data.append("metaTagDesc", this.gallery.metaTagDesc || this.gallery.leadTitle);
data.append("customDate", this.gallery.customDate);
if (this.gallery.newsFileId) {
data.append("newsFileId", this.gallery.newsFileId);
}
this.$axios
.put(`/api/admin/gallery/${this.gallery._id}`, data, this.axiosConfig)
.then((response) => {
this.$message({
type: "success",
message: "اطلاعات بروزرسانی شد.",
});
this.$nuxt.refresh();
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
if (err.response.status === 500) {
return this.$message({
type: "error",
message: "مشکلی در ارسال درخواست پیش آمده",
});
}
if (err.response.status === 422)
this.validation = err.response.data.validation;
else console.log(err.response.data);
});
},
},
head() {
return {
title: this.title,
};
},
layout: "admin",
async asyncData({$axios, $auth, params, query, error}) {
try {
const portals = await $axios.get("/api/admin/portals" , {process : false});
const parents = await $axios.get("/api/admin/category/getParent" , {
params: {
type: "news",
}
});
const newsFile = await $axios.get(`/api/admin/newsFile`, {progress: false})
var setModelType =
$auth.user.portals.length !== 1 ?
$auth.user.portals :
$auth.user.portals[0];
const setFilterParent =
$auth.user.portals.length !== 1
? null
: parents.data.filter(
(item) => item.modelType === $auth.user.portals[0]
);
if (params.details !== "new") {
const gallery = await $axios.get(`/api/admin/gallery/${params.details}`);
return {
portals: portals.data,
gallery: gallery.data,
parents: parents.data,
filterParent: parents.data,
newsFile: newsFile.data,
showSectionUpload: true,
checkGalleryType: gallery.data.galleryType
};
} else {
return {
portals: portals.data,
parents: parents.data,
newsFile: newsFile.data,
filterParent: setFilterParent,
gallery: {
title: '',
summaryTitle: '',
leadTitle: '',
catId: $auth.user.specialPermissions,
priority: 0,
isEmbedded: false,
embeddedCode: '',
showInHome: true,
siteMap: true,
special: false,
publish: true,
galleryType: '',
keywords: [],
favorite: false,
galleryStatus: false,
modelType: setModelType,
},
};
}
} catch (e) {
if (e?.response?.status === 401) {
error({
status: 401,
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (e?.response?.status === 403) {
error({
status: 403,
message: e?.response?.data?.message,
});
}
if (e?.response?.status === 500) {
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات پیش آمده",
});
} else
error({
status: 404,
message: "رسانه مورد نظر پیدا نشد",
});
}
},
};
</script>
+436
View File
@@ -0,0 +1,436 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="success" :to="{ name: 'admin-gallery-details', params: { details: 'new' } }"
class="mr-auto">افزودن</CButton>
</CustomSubHeader>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-filter"></i>
<span style="color:#000">فیلتر</span>
</slot>
</CCardHeader>
<CCardBody>
<CRow>
<CCol md="6">
<CRow style="flex-direction : column;">
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>عنوان</span>
</CCol>
<CCol col="md-9">
<el-input style="width : 100%" placeholder="" v-model="search.term"></el-input>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>نوع گالری</span>
</CCol>
<CCol col="md-9">
<el-select filterable clearable style="width : 100%" v-model="search.galleryType"
placeholder="">
<el-option key="image" label="عکس" value="image">
</el-option>
<el-option key="graphic" label="گرافیک" value="graphic">
</el-option>
<el-option key="video" label="فیلم" value="video">
</el-option>
</el-select>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>قسمت</span>
</CCol>
<CCol col="md-9">
<el-select v-model="search.portals" clearable style="width : 100%">
<el-option v-for="item in portals" :key="item.value" :label="item.name" :value="item.value">
</el-option>
</el-select>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>تاریخ</span>
</CCol>
<CCol col="md-9">
<date-picker range clearable format="YYYY-MM-DD" display-format="jMMMM jD" v-model="search.date"></date-picker>
</CCol>
</CRow>
</CCol>
</CRow>
</CCol>
<CCol md="6">
<CRow style="flex-direction : column;">
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>دسته بندی</span>
</CCol>
<CCol col="md-9">
<el-select filterable clearable style="width : 100%" v-model="search.catId"
placeholder="انتخاب دسته بندی">
<el-option v-for="item in parents" :key="item._id" :label="item.title" :value="item._id">
<!-- <span>{{setTitle(item)}}</span> -->
</el-option>
</el-select>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>وضعیت گالری</span>
</CCol>
<CCol col="md-9">
<el-select v-model="search.galleryStatus" clearable style="width : 100%">
<el-option :key="true" label="کامل" :value="true">
</el-option>
<el-option :key="false" label="ناقص" :value="false">
</el-option>
</el-select>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>وضعیت انتشار</span>
</CCol>
<CCol col="md-9">
<el-select v-model="search.publish" clearable style="width : 100%">
<el-option :key="true" label="منتشر شده" :value="true">
</el-option>
<el-option :key="false" label="منتشر نشده" :value="false">
</el-option>
</el-select>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3" v-if="$auth.user.permissions.includes('superAdmin')">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>نمایش در صفحه اصلی</span>
</CCol>
<CCol col="md-9">
<el-select v-model="search.showInHome" clearable style="width : 100%">
<el-option :key="true" label="بله" :value="true">
</el-option>
<el-option :key="false" label="خیر" :value="false">
</el-option>
</el-select>
</CCol>
</CRow>
</CCol>
</CRow>
</CCol>
</CRow>
<CRow>
<el-button :loading="loading" @click="handleSearch" size="small" style="width: auto;margin: 25px auto auto auto;" type="primary"
icon="el-icon-search">
جست و جو</el-button>
</CRow>
</CCardBody>
</CCard>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>{{ list_title }}</span>
</slot>
<slot> </slot>
</CCardHeader>
<CCardBody>
<el-table v-loading="loading" :data="gallery.docs" style="width: 100%">
<el-table-column type="index" label="#"> </el-table-column>
<el-table-column label="عنوان">
<template slot-scope="scope">
<span class="title">
<el-popover placement="top-end" trigger="hover" :content="scope.row.title">
<i v-if="scope.row.title.length > 25" class="el-icon-info" slot="reference"></i>
</el-popover>
{{ scope.row.title }}
</span>
</template>
</el-table-column>
<el-table-column label="کاربر">
<template slot-scope="scope">
<span v-if="!$auth.user.permissions.includes('superAdmin')">{{
scope.row._creator.firstName + " " + scope.row._creator.lastName
}}</span>
<nuxt-link v-else :to="{
name: 'admin-users-profile',
params: { profile: scope.row._creator._id },
}"><span style="color: blue;">{{
scope.row._creator.firstName +
" " +
scope.row._creator.lastName
}}</span></nuxt-link>
</template>
</el-table-column>
<el-table-column prop="catId.title" label="دسته بندی" width="">
<!-- <template slot-scope="scope">-->
<!-- <span>{{ scope.row.catId.title }}</span>-->
<!-- </template>-->
</el-table-column>
<el-table-column label="نوع رسانه" width="">
<template slot-scope="scope">
<el-tag type="primary">{{
scope.row.galleryType === 'image' ? 'عکس' : scope.row.galleryType === 'video' ? 'فیلم' : 'گرافیک'
}}</el-tag>
</template>
</el-table-column>
<el-table-column label="وضعیت رسانه" width="">
<template slot-scope="scope">
<el-tag :type="scope.row.galleryStatus ? 'success' : 'danger'">{{
scope.row.galleryStatus ? "کامل" : "ناقص"
}}</el-tag>
</template>
</el-table-column>
<el-table-column v-if="$auth.user.permissions.includes('superAdmin')" label="نمایش در صفحه اصلی" width="">
<template slot-scope="scope">
<el-tag :type="scope.row.showInHome ? 'primary' : 'danger'">{{
scope.row.showInHome ? "بله" : "خیر"
}}
</el-tag>
</template>
</el-table-column>
<el-table-column label="وضعیت انتشار" width="">
<template slot-scope="scope">
<el-tag :type="scope.row.publish ? 'primary' : 'danger'">{{
scope.row.publish ? "منتشر شده" : "منتشر نشده"
}}</el-tag>
</template>
</el-table-column>
<el-table-column label="تاریخ ایجاد" width="">
<template slot-scope="scope">
<span>{{ jDate(scope.row.created_at) }}</span>
</template>
</el-table-column>
<el-table-column label="ویرایش" width="110" align="center">
<template slot-scope="scope">
<CButton color="danger" variant="outline" :key="scope.row._id + Math.random()"
@click="deleteGallery(scope.row._id)">
<i class="far fa-trash-alt"></i>
</CButton>
<CButton color="success" variant="outline" :key="scope.row._id" :to="{
name: 'admin-gallery-details',
params: { details: scope.row._id },
}">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
<CCard class="col" v-if="gallery.totalDocs>5">
<CRow alignHorizontal="center" style="padding : 10px">
<el-pagination :hide-on-single-page="true" layout="prev, pager, next" :page-size="gallery.limit"
@current-change="handleCurrentChange" :current-page.sync="gallery.page" :total="gallery.totalDocs">
</el-pagination>
</CRow>
</CCard>
</div>
</template>
<script>
import moment from "moment-jalaali";
const _ = require('lodash');
export default {
data() {
return {
title: "لیست رسانه ها",
list_title: "لیست",
gallery: null,
search: {},
loading : false
};
},
computed: {
pageQuery() {
return this.$route.query.page;
}
},
watch: {
pageQuery(newPage, oldPage) {
this.$nuxt.refresh();
}
},
methods: {
jDate(date) {
return moment(date).format("jYYYY/jMM/jDD");
},
handleCurrentChange(page) {
if (!_.isEmpty(this.search)) {
this.handleSearch(page);
} else {
this.$router.push({
name: "admin-gallery",
query: {
page: page
}
});
}
},
handleSearch(page) {
this.loading = true;
const data = {
term: this.search.term,
catId: this.search.catId,
galleryStatus: this.search.galleryStatus,
showInHome: this.search.showInHome,
portals: this.search.portals,
publish: this.search.publish,
galleryType: this.search.galleryType,
date: this.search.date,
}
this.$axios.post(`/api/admin/gallery/search?page=${page}`, data, this.axiosConfig)
.then((result) => {
/** get name of portal */
for (const item of result.data.docs) {
item.modelType = this.portals.filter((value) => value.value === item.modelType)[0].name;
}
this.gallery = result.data;
this.loading = false;
})
.catch(err => {
this.loading = false;
if (err.response.status === 401) {
return this.$message({
type: 'error',
message: 'لطفا دوباره وارد سیستم شوید.'
})
}
if (err.response.status === 422) this.validation = err.response.data.validation
else console.log(err.response.data)
})
},
deleteGallery(id) {
this.$confirm("رسانه حذف شود؟", "هشدار", {
confirmButtonText: "بله",
cancelButtonText: "لغو",
type: "warning",
})
.then(async () => {
this.$axios
.delete(`/api/admin/gallery/${id}`)
.then((res) => {
this.$message({
type: "success",
message: "رسانه با موفقیت حذف شد",
});
this.$nuxt.refresh();
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
if (err.response.status === 422) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
console.log(err.response.data);
});
})
.catch(() => {
this.$message({
type: "warning",
message: "عملیات لغو شد",
});
});
},
},
head() {
return {
title: this.title,
};
},
layout: "admin",
async asyncData({
$axios,
query,
error
}) {
try {
// const gallery = await $axios.get(`/api/admin/gallery?page=${query.page}`, { progress: false });
// const portals = await $axios.get(`/api/admin/portals`, { progress: false });
const requests = [
$axios.get(`/api/admin/gallery?page=${query.page}`, { progress: false }),
$axios.get(`/api/admin/portals`, { progress: false }),
$axios.get("/api/admin/category/getParent", {
params: {
type: "news",
},
})
];
const fetch = await Promise.all(requests);
let [gallery, portals , parents] = fetch;
/** get name of portal */
for (const item of gallery.data.docs) {
item.modelType = portals.data.filter((value) => value.value === item.modelType)[0].name;
}
return {
gallery: gallery.data,
portals: portals.data,
parents: parents.data,
};
} catch (e) {
console.log(e);
if(e?.response?.status === 401){
error({
status: 401,
message: 'شما اجازه دسترسی به این صفحه را ندارید'
})
}else{
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات بوجود آمده است",
});
}
}
},
};
</script>
+440
View File
@@ -0,0 +1,440 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="primary" class="mr-auto" :to="{ name: 'admin' }">برگشت به صفحه داشبورد</CButton>
</CustomSubHeader>
<CCard>
<CCardBody>
<CRow>
<CCol>
<nuxt-link :to="{name: 'admin-homePageManagement',query: {portal: 'ostandari'}}">
<el-button :type="portalQuery === 'ostandari' ? 'success' : 'info'">استانداری</el-button>
</nuxt-link>
<nuxt-link :to="{name: 'admin-homePageManagement',query: {portal: 'election'}}">
<el-button :type="portalQuery === 'election' ? 'success' : 'info'">انتخابات</el-button>
</nuxt-link>
</CCol>
</CRow>
</CCardBody>
</CCard>
<CCard>
<CCardBody>
<CRow>
<CCol>
<div class="homePageTemplate">
<section class="s1">
<div class="container">
<div class="row">
<div class="col-12">
<div class="imgBox">
<img src="~/assets/admin/img/homePageTemplate/s1.jpg" alt="">
<div class="elementTemp">
<div class="relativePos">
<div class="txtBox">
<h2>
<span> اسلایدر </span>
<span v-if="portalQuery === 'ostandari'">(استانداری)</span>
<span v-else>(انتخابات)</span>
</h2>
<p class="description">
<span>از منوی </span>
<nuxt-link :to="{name: 'admin-slider'}">"تنظیمات > مدیریت اسلایدر"</nuxt-link>
<span>برای تغییر این بخش استفاده کنید</span>
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<div class="otherSections">
<div class="container">
<div class="row">
<main class="col-10">
<section class="s2">
<div class="imgBox">
<img src="~/assets/admin/img/homePageTemplate/s2.jpg" alt="">
<div class="elementTemp">
<div class="relativePos">
<div class="txtBox">
<h2>
<span> قسمت دوم </span>
<span v-if="portalQuery === 'ostandari'">(استانداری)</span>
<span v-else>(انتخابات)</span>
</h2>
<div class="list">
<el-select v-model="homePage.s2" filterable :popper-append-to-body="false">
<el-option value="" label="همه"></el-option>
<el-option v-for="item in filteredCategories" :key="item._id + 1" :value="item._id" :label="item.title"></el-option>
</el-select>
<el-button size="small" class="mr-1" type="success" @click="update">بروزرسانی</el-button>
</div>
</div>
</div>
</div>
</div>
</section>
<section class="s3">
<div class="imgBox">
<img src="~/assets/admin/img/homePageTemplate/s3.jpg" alt="">
<div class="elementTemp">
<div class="relativePos">
<div class="txtBox">
<h2>
<span> قسمت سوم </span>
<span v-if="portalQuery === 'ostandari'">(استانداری)</span>
<span v-else>(انتخابات)</span>
</h2>
<div class="list">
<el-select v-model="homePage.s3" filterable :popper-append-to-body="false">
<el-option value="" label="همه"></el-option>
<el-option v-for="item in filteredCategories" :key="item._id + 2" :value="item._id" :label="item.title"></el-option>
</el-select>
<el-button size="small" class="mr-1" type="success" @click="update">بروزرسانی</el-button>
</div>
</div>
</div>
</div>
</div>
</section>
<section class="s4">
<div class="imgBox">
<img src="~/assets/admin/img/homePageTemplate/s4.jpg" alt="">
<div class="elementTemp">
<div class="relativePos">
<div class="txtBox">
<h2>
<span> قسمت چهارم </span>
<span v-if="portalQuery === 'ostandari'">(استانداری)</span>
<span v-else>(انتخابات)</span>
</h2>
<div class="list">
<el-select v-model="homePage.s4" filterable :popper-append-to-body="false">
<el-option v-for="item in filteredRootParents" :key="item._id + 3" :value="item._id" :label="item.title"></el-option>
</el-select>
<el-button size="small" class="mr-1" type="success" @click="update">بروزرسانی</el-button>
</div>
</div>
</div>
</div>
</div>
</section>
<section class="s5">
<div class="imgBox">
<img src="~/assets/admin/img/homePageTemplate/s5.jpg" alt="">
<div class="elementTemp">
<div class="relativePos">
<div class="txtBox">
<h2>
<span> قسمت پنجم </span>
<span v-if="portalQuery === 'ostandari'">(استانداری)</span>
<span v-else>(انتخابات)</span>
</h2>
<div class="list">
<el-select v-model="homePage.s5" filterable :popper-append-to-body="false" multiple>
<el-option v-for="item in filteredRootParents" :key="item._id + 4" :value="item._id" :label="item.title"></el-option>
</el-select>
<el-button size="small" class="mr-1" type="success" @click="update">بروزرسانی</el-button>
</div>
</div>
</div>
</div>
</div>
</section>
<section class="s6">
<div class="imgBox">
<img src="~/assets/admin/img/homePageTemplate/s6.jpg" alt="">
<div class="elementTemp">
<div class="relativePos">
<div class="txtBox">
<h2>
<span> قسمت ششم </span>
<span v-if="portalQuery === 'ostandari'">(استانداری)</span>
<span v-else>(انتخابات)</span>
</h2>
<div class="list">
<el-select v-model="homePage.s6" filterable :popper-append-to-body="false">
<el-option value="" label="همه"></el-option>
<el-option v-for="item in filteredCategories" :key="item._id + 5" :value="item._id" :label="item.title"></el-option>
</el-select>
<el-button size="small" class="mr-1" type="success" @click="update">بروزرسانی</el-button>
</div>
</div>
</div>
</div>
</div>
</section>
</main>
<aside class="col-2">
<section class="s1-side">
<div class="imgBox">
<img src="~/assets/admin/img/homePageTemplate/s1-side.jpg" alt="">
<div class="elementTemp">
<div class="relativePos">
<div class="txtBox">
<h2>استاندار</h2>
<p class="description">
<span>از منوی </span>
<nuxt-link :to="{name: 'admin-contents-details',params: {details: 'manager'}}">"تنظیمات > استاندار"</nuxt-link>
<span>برای تغییر این بخش استفاده کنید</span>
</p>
</div>
</div>
</div>
</div>
</section>
<section class="s2-side">
<div class="imgBox">
<img src="~/assets/admin/img/homePageTemplate/s2-side.jpg" alt="">
<div class="elementTemp">
<div class="relativePos">
<div class="txtBox">
<h2>
<span> گرازش تصویری </span>
<span v-if="portalQuery === 'ostandari'">(استانداری)</span>
<span v-else>(انتخابات)</span>
</h2>
<div class="list">
<el-select v-model="homePage.s2Side" filterable :popper-append-to-body="false">
<el-option value="" label="همه"></el-option>
<el-option v-for="item in filteredCategories" :key="item._id + 6" :value="item._id" :label="item.title"></el-option>
</el-select>
<el-button size="small" class="mr-1" type="success" @click="update">بروزرسانی</el-button>
</div>
</div>
</div>
</div>
</div>
</section>
<section class="s3-side">
<div class="imgBox">
<img src="~/assets/admin/img/homePageTemplate/s3-side.jpg" alt="">
<div class="elementTemp">
<div class="relativePos">
<div class="txtBox">
<h2>
<span> فیلم ها </span>
<span v-if="portalQuery === 'ostandari'">(استانداری)</span>
<span v-else>(انتخابات)</span>
</h2>
<div class="list">
<el-select v-model="homePage.s3Side" filterable :popper-append-to-body="false">
<el-option value="" label="همه"></el-option>
<el-option v-for="item in filteredCategories" :key="item._id + 7" :value="item._id" :label="item.title"></el-option>
</el-select>
<el-button size="small" class="mr-1" type="success" @click="update">بروزرسانی</el-button>
</div>
</div>
</div>
</div>
</div>
</section>
<section class="s4-side">
<div class="imgBox">
<img src="~/assets/admin/img/homePageTemplate/s4-side.jpg" alt="">
<div class="elementTemp">
<div class="relativePos">
<div class="txtBox">
<h2>
<span> گرافیک ها </span>
<span v-if="portalQuery === 'ostandari'">(استانداری)</span>
<span v-else>(انتخابات)</span>
</h2>
<div class="list">
<el-select v-model="homePage.s4Side" filterable :popper-append-to-body="false">
<el-option value="" label="همه"></el-option>
<el-option v-for="item in filteredCategories" :key="item._id + 8" :value="item._id" :label="item.title"></el-option>
</el-select>
<el-button size="small" class="mr-1" type="success" @click="update">بروزرسانی</el-button>
</div>
</div>
</div>
</div>
</div>
</section>
<section class="s5-side">
<div class="imgBox">
<img src="~/assets/admin/img/homePageTemplate/s5-side.jpg" alt="">
<div class="elementTemp">
<div class="relativePos">
<div class="txtBox">
<h2>
<span> مطالب ویژه و اطلاعیه ها</span>
<span v-if="portalQuery === 'ostandari'">(استانداری)</span>
<span v-else>(انتخابات)</span>
</h2>
<div class="list">
<el-select v-model="homePage.s5Side" filterable :popper-append-to-body="false">
<el-option value="" label="همه"></el-option>
<el-option v-for="item in filteredCategories" :key="item._id + 9" :value="item._id" :label="item.title"></el-option>
</el-select>
<el-button size="small" class="mr-1" type="success" @click="update">بروزرسانی</el-button>
</div>
</div>
</div>
</div>
</div>
</section>
<section class="s6-side">
<div class="imgBox">
<img src="~/assets/admin/img/homePageTemplate/s6-side.jpg" alt="">
<div class="elementTemp">
<div class="relativePos">
<div class="txtBox">
<h2>
<span> آخرین اخبار </span>
<span v-if="portalQuery === 'ostandari'">(استانداری)</span>
<span v-else>(انتخابات)</span>
</h2>
<div class="list">
<el-select v-model="homePage.s6Side" filterable :popper-append-to-body="false">
<el-option value="" label="همه"></el-option>
<el-option v-for="item in filteredCategories" :key="item._id + 10" :value="item._id" :label="item.title"></el-option>
</el-select>
<el-button size="small" class="mr-1" type="success" @click="update">بروزرسانی</el-button>
</div>
</div>
</div>
</div>
</div>
</section>
<section class="s7-side">
<div class="imgBox">
<img src="~/assets/admin/img/homePageTemplate/s7-side.jpg" alt="">
<div class="elementTemp">
<div class="relativePos">
<div class="txtBox">
<h2>پیوند ها</h2>
<p class="description">
<span>از منوی </span>
<nuxt-link :to="{name: 'admin-links'}">"تنظیمات > مدیریت پیوند ها"</nuxt-link>
<span>برای تغییر این بخش استفاده کنید</span>
</p>
</div>
</div>
</div>
</div>
</section>
</aside>
</div>
</div>
</div>
</div>
</CCol>
</CRow>
</CCardBody>
</CCard>
</div>
</template>
<script>
export default {
data() {
return {
title: 'مدیریت صفحه اصلی سایت',
categories: null,
rootParents: null,
homePage: null
}
},
computed: {
portalQuery() {
return this.$route.query.portal
},
filteredCategories() {
return this.categories.filter(item => item.modelType === this.portalQuery)
},
filteredRootParents() {
return this.rootParents.categories.filter(item => item.modelType === this.portalQuery)
}
},
watch: {
portalQuery(newVal, oldVal) {
this.$nuxt.refresh()
}
},
methods: {
update() {
this.$axios
.post(`/api/admin/homePageSettings?portal=${this.portalQuery}`, this.homePage)
.then((response) => {
this.$message({
type: "success",
message: "اطلاعات بروزرسانی شد.",
});
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
if (err.response.status === 500) {
return this.$message({
type: "error",
message: "مشکلی در ارسال درخواست پیش آمده",
});
}
if (err.response.status === 422) {
this.$message({
type: 'warning',
message: 'پارامترها رو بررسی کنید'
})
this.validation = err.response.data.validation;
} else console.log(err.response.data);
});
}
},
head() {
return {
title: this.title,
}
},
layout: "admin",
async asyncData({$axios, error, query}) {
try {
const categories = await $axios.get('/api/admin/category/getParent')
const rootParents = await $axios.get('/api/public/getMenu')
const homePage = await $axios.get(`/api/admin/homePageSettings`, {params: {portal: query.portal}})
return {
categories: categories.data,
rootParents: rootParents.data,
homePage: homePage.data
}
} catch (e) {
error({status: 500, message: ''})
}
}
}
</script>
+667
View File
@@ -0,0 +1,667 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
</CustomSubHeader>
<CCard>
<CCardBody>
<CRow>
<CCol>
<nuxt-link :to="{name: 'admin-homePageNews',query: {portal: 'ostandari'}}">
<el-button :type="portalQuery === 'ostandari' ? 'success' : 'info'">استانداری</el-button>
</nuxt-link>
<nuxt-link :to="{name: 'admin-homePageNews',query: {portal: 'election'}}">
<el-button :type="portalQuery === 'election' ? 'success' : 'info'">انتخابات</el-button>
</nuxt-link>
</CCol>
</CRow>
</CCardBody>
</CCard>
<!--------------------------------------------- section s2 --------------------------------------------->
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>اخبار قسمت دوم</span>
</slot>
<slot></slot>
</CCardHeader>
<CCardBody>
<el-table
:data="homeItems.s2"
:default-sort="{ prop: 'date', order: 'descending' }"
key="tableS2"
style="width: 100%">
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
label="تصویر"
width="200">
<template slot-scope="scope">
<img :src="scope.row.thumbCover" alt="" style="width: 100%;">
</template>
</el-table-column>
<el-table-column
prop="title"
label="عنوان">
</el-table-column>
<el-table-column
label="تاریخ ایجاد"
width="">
<template slot-scope="scope">
<span>{{ jDate(scope.row.created_at) }}</span>
</template>
</el-table-column>
<el-table-column
label="ویرایش"
width="75"
align="center">
<template slot-scope="scope">
<CButton color="warning" variant="outline" @click="removeFromHome('news',scope.row._id)">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
<!--------------------------------------------- section s2 --------------------------------------------->
<!--------------------------------------------- section s3 --------------------------------------------->
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>پرونده های خبری قسمت سوم</span>
</slot>
<slot></slot>
</CCardHeader>
<CCardBody>
<el-table
:data="homeItems.s3"
key="tableS3"
style="width: 100%"
>
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
prop="title"
label="عنوان">
</el-table-column>
<el-table-column
label="تاریخ ایجاد"
width="">
<template slot-scope="scope">
<span>{{ jDate(scope.row.created_at) }}</span>
</template>
</el-table-column>
<el-table-column
label="ویرایش"
width="75"
align="center">
<template slot-scope="scope">
<CButton color="warning" variant="outline" @click="removeFromHome('newsFile',scope.row._id)">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
<!--------------------------------------------- section s3 --------------------------------------------->
<!--------------------------------------------- section s4 --------------------------------------------->
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>اخبار قسمت چهارم</span>
</slot>
<slot></slot>
</CCardHeader>
<CCardBody>
<el-table
:data="homeItems.s4.news"
style="width: 100%"
key="tableS4"
>
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
label="تصویر"
width="200">
<template slot-scope="scope">
<img :src="scope.row.thumbCover" alt="" style="width: 100%;">
</template>
</el-table-column>
<el-table-column
prop="title"
label="عنوان">
</el-table-column>
<el-table-column
label="تاریخ ایجاد"
width="">
<template slot-scope="scope">
<span>{{ jDate(scope.row.created_at) }}</span>
</template>
</el-table-column>
<el-table-column
label="ویرایش"
width="75"
align="center">
<template slot-scope="scope">
<CButton color="warning" variant="outline" @click="removeFromHome('news',scope.row._id)">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
<!--------------------------------------------- section s4 --------------------------------------------->
<!--------------------------------------------- section s5 --------------------------------------------->
<CCard
v-for="(item,index) in homeItems.s5"
:key="'CCardItem'+index"
>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>اخبار قسمت پنجم ({{ item.nameTag }}) </span>
</slot>
<slot></slot>
</CCardHeader>
<CCardBody>
<el-table
:data="item.news"
style="width: 100%"
:key="'tableS5'+index"
>
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
prop="title"
label="عنوان">
</el-table-column>
<el-table-column
label="تاریخ ایجاد"
width="">
<template slot-scope="scope">
<span>{{ jDate(scope.row.created_at) }}</span>
</template>
</el-table-column>
<el-table-column
label="ویرایش"
width="75"
align="center">
<template slot-scope="scope">
<CButton color="warning" variant="outline" @click="removeFromHome('news',scope.row._id)">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
<!--------------------------------------------- section s5 --------------------------------------------->
<!--------------------------------------------- section s6 --------------------------------------------->
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>اخبار قسمت ششم</span>
</slot>
<slot></slot>
</CCardHeader>
<CCardBody>
<el-table
:data="homeItems.s6"
key="tableS6"
style="width: 100%"
>
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
label="تصویر"
width="200">
<template slot-scope="scope">
<img :src="scope.row.thumbCover" alt="" style="width: 100%;">
</template>
</el-table-column>
<el-table-column
prop="title"
label="عنوان">
</el-table-column>
<el-table-column
label="تاریخ ایجاد"
width="">
<template slot-scope="scope">
<span>{{ jDate(scope.row.created_at) }}</span>
</template>
</el-table-column>
<el-table-column
label="ویرایش"
width="75"
align="center">
<template slot-scope="scope">
<CButton color="warning" variant="outline" @click="removeFromHome('news',scope.row._id)">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
<!--------------------------------------------- section s6 --------------------------------------------->
<!--------------------------------------------- section s2Side --------------------------------------------->
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>خبر گزارش تصویری سایدبار</span>
</slot>
<slot></slot>
</CCardHeader>
<CCardBody>
<el-table
:data="homeItems.s2Side"
key="tableS6"
style="width: 100%"
>
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
label="تصویر"
width="200">
<template slot-scope="scope">
<img :src="scope.row.thumbCover" alt="" style="width: 100%;">
</template>
</el-table-column>
<el-table-column
prop="title"
label="عنوان">
</el-table-column>
<el-table-column
label="تاریخ ایجاد"
width="">
<template slot-scope="scope">
<span>{{ jDate(scope.row.created_at) }}</span>
</template>
</el-table-column>
<el-table-column
label="ویرایش"
width="75"
align="center">
<template slot-scope="scope">
<CButton color="warning" variant="outline" @click="removeFromHome('media',scope.row._id)">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
<!--------------------------------------------- section s2Side --------------------------------------------->
<!--------------------------------------------- section s3Side --------------------------------------------->
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>خبر فیلم سایدبار</span>
</slot>
<slot></slot>
</CCardHeader>
<CCardBody>
<el-table
:data="homeItems.s3Side"
key="tableS6"
style="width: 100%"
>
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
label="تصویر"
width="200">
<template slot-scope="scope">
<img :src="scope.row.thumbCover" alt="" style="width: 100%;">
</template>
</el-table-column>
<el-table-column
prop="title"
label="عنوان">
</el-table-column>
<el-table-column
label="تاریخ ایجاد"
width="">
<template slot-scope="scope">
<span>{{ jDate(scope.row.created_at) }}</span>
</template>
</el-table-column>
<el-table-column
label="ویرایش"
width="75"
align="center">
<template slot-scope="scope">
<CButton color="warning" variant="outline" @click="removeFromHome('media',scope.row._id)">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
<!--------------------------------------------- section s3Side --------------------------------------------->
<!--------------------------------------------- section s4Side --------------------------------------------->
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>خبر گرافیک سایدبار</span>
</slot>
<slot></slot>
</CCardHeader>
<CCardBody>
<el-table
:data="homeItems.s4Side"
key="tableS6"
style="width: 100%"
>
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
label="تصویر"
width="200">
<template slot-scope="scope">
<img :src="scope.row.thumbCover" alt="" style="width: 100%;">
</template>
</el-table-column>
<el-table-column
prop="title"
label="عنوان">
</el-table-column>
<el-table-column
label="تاریخ ایجاد"
width="">
<template slot-scope="scope">
<span>{{ jDate(scope.row.created_at) }}</span>
</template>
</el-table-column>
<el-table-column
label="ویرایش"
width="75"
align="center">
<template slot-scope="scope">
<CButton color="warning" variant="outline" @click="removeFromHome('media',scope.row._id)">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
<!--------------------------------------------- section s4Side --------------------------------------------->
<!--------------------------------------------- section s5Side --------------------------------------------->
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>اخبار مطالب ویژه سایدبار</span>
</slot>
<slot></slot>
</CCardHeader>
<CCardBody>
<el-table
:data="homeItems.s5Side"
key="tableS6"
style="width: 100%"
>
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
label="تصویر"
width="200">
<template slot-scope="scope">
<img :src="scope.row.thumbCover" alt="" style="width: 100%;">
</template>
</el-table-column>
<el-table-column
prop="title"
label="عنوان">
</el-table-column>
<el-table-column
label="تاریخ ایجاد"
width="">
<template slot-scope="scope">
<span>{{ jDate(scope.row.created_at) }}</span>
</template>
</el-table-column>
<el-table-column
label="ویرایش"
width="75"
align="center">
<template slot-scope="scope">
<CButton color="warning" variant="outline" @click="removeFromHome('news',scope.row._id)">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
<!--------------------------------------------- section s5Side --------------------------------------------->
<!--------------------------------------------- section s6Side --------------------------------------------->
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>آخرین اخبار سایدبار</span>
</slot>
<slot></slot>
</CCardHeader>
<CCardBody>
<el-table
:data="homeItems.s6Side"
key="tableS6"
style="width: 100%"
>
<el-table-column
type="index"
label="#">
</el-table-column>
<el-table-column
prop="title"
label="عنوان">
</el-table-column>
<el-table-column
label="تاریخ ایجاد"
width="">
<template slot-scope="scope">
<span>{{ jDate(scope.row.created_at) }}</span>
</template>
</el-table-column>
<el-table-column
label="ویرایش"
width="75"
align="center">
<template slot-scope="scope">
<CButton color="warning" variant="outline" @click="removeFromHome('news',scope.row._id)">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
<!--------------------------------------------- section s6Side --------------------------------------------->
</div>
</template>
<script>
import moment from "moment-jalaali"
export default {
data() {
return {
title: "لیست اخباری روی صفحه اصلی",
list_title: "لیست",
links: null,
homeItems: null
}
},
computed: {
portalQuery() {
return this.$route.query.portal
}
},
methods: {
jDate(date) {
return moment(date).format("jYYYY/jMM/jDD")
},
removeFromHome(type, id) {
this.$confirm("این مورد از صفحه اصلی قابل مشاهده نباشد؟", "هشدار", {
confirmButtonText: "بله",
cancelButtonText: "لغو",
type: "warning",
})
.then(async () => {
this.$axios.put(`/api/admin/changeShowInHome`, {
id: id,
modelName: type
})
.then((res) => {
this.$message({
type: "success",
message: 'عملیات با موفیقت انجام شد',
})
this.$nuxt.refresh()
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید.",
})
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message,
})
}
if (err.response.status === 422) {
return this.$message({
type: "error",
message: err.response.data.message,
})
}
console.log(err.response.data);
})
})
.catch(() => {
this.$message({
type: "warning",
message: "عملیات لغو شد",
})
})
},
},
watch: {
portalQuery(newVal, oldVal) {
this.$nuxt.refresh()
}
},
head() {
return {
title: this.title,
}
},
layout: "admin",
async asyncData({$axios, error, query}) {
try {
const homeItems = await $axios.get('/api/public/home', {params: {portal: query.portal}})
const links = await $axios.get(`/api/admin/links`)
return {
links: links.data,
homeItems: homeItems.data
}
} catch (e) {
if (e?.response?.status === 401) error({status: 401, message: 'شما اجازه دسترسی به این صفحه را ندارید'})
else error({status: 500, message: "مشکلی در گرفتن اطلاعات بوجود آمده است"})
}
},
};
</script>
+159
View File
@@ -0,0 +1,159 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
</CustomSubHeader>
<template v-if="$auth.user.permissions.includes('superAdmin')">
<CCard>
<CCardBody>
<CRow>
<CCol col="12" sm="3">
<CCallout color="info">
<small class="text-muted">تعداد ادمین ها</small><br>
<strong class="h4">{{ countUser }}</strong>
</CCallout>
</CCol>
<CCol col="12" sm="3">
<CCallout color="danger">
<small class="text-muted">تعداد اخبار</small><br>
<strong class="h4">{{ countNews }}</strong>
</CCallout>
</CCol>
<CCol col="12" sm="3">
<CCallout color="success">
<small class="text-muted">تعداد رسانه ها</small><br>
<strong class="h4">{{ countGallery }}</strong>
</CCallout>
</CCol>
<CCol col="12" sm="3">
<CCallout color="warning">
<small class="text-muted">تعداد پرونده خبری</small><br>
<strong class="h4">{{ countFileNews }}</strong>
</CCallout>
</CCol>
</CRow>
</CCardBody>
</CCard>
<CRow>
<CCol col="12" sm="6">
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>پر بازدیدترین اخبار</span>
</slot>
<slot></slot>
</CCardHeader>
<CCardBody>
<div class="mb-3" v-for="(item , index) in popNews.docs" :key="item._id">
<nuxt-link class="mainLink" :to="{name: 'admin-news-details',params: { details: item._id }}">
<span class="numberMain">{{ index + 1 }}</span>
<span class="descMain">{{ item.title }}</span>
</nuxt-link>
</div>
</CCardBody>
</CCard>
</CCol>
<CCol col="12" sm="6">
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>جدیدترین اخبار</span>
</slot>
<slot></slot>
</CCardHeader>
<CCardBody>
<div class="mb-3" v-for="(item , index) in newNews.docs" :key="item._id">
<nuxt-link class="mainLink" :to="{name: 'admin-news-details',params: { details: item._id }}">
<span class="numberMain">{{ index + 1 }}</span>
<span class="descMain">{{ item.title }}</span>
</nuxt-link>
</div>
</CCardBody>
</CCard>
</CCol>
</CRow>
</template>
<template v-else>
<CCard>
<CCardBody>
<CRow>
<CCol>
<h1> پرتال استانداری</h1>
</CCol>
</CRow>
</CCardBody>
</CCard>
</template>
</div>
</template>
<script>
import moment from "moment-jalaali";
export default {
data() {
return {
title: 'داشبورد',
list_title: 'لیست',
countUser: null,
countNews: null,
countGallery: null,
countFileNews: null,
popNews: [],
newNews: []
}
},
computed: {},
methods: {
jDate(date) {
return moment(date).format("jYYYY/jMM/jDD")
},
},
head() {
return {
title: this.title
}
},
layout: 'admin',
async asyncData({$axios, $auth, error}) {
try {
// let returnObj = {};
if ($auth.user.permissions.includes('superAdmin')) {
const requests = [
$axios.get(`/api/admin/user`, {progress: false}),
$axios.get(`/api/admin/news`, {progress: false}),
$axios.get(`/api/admin/gallery`, {progress: false}),
$axios.get(`/api/admin/newsFile`, {progress: false}),
$axios.get(`/api/public/getNews?flag=popular&portal=ostandari`, {progress: false}),
$axios.get(`/api/public/getNews?flag=new&portal=ostandari`)
];
const fetch = await Promise.all(requests);
const [countUser, countNews, countGallery, countFileNews, popNews, newNews] = fetch;
return {
countUser: countUser.data.totalDocs,
countNews: countNews.data.totalDocs,
countGallery: countGallery.data.totalDocs,
countFileNews: countFileNews.data.length,
popNews: popNews.data,
newNews: newNews.data,
}
}
} catch (e) {
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات بوجود آمده است",
});
}
}
}
</script>
+334
View File
@@ -0,0 +1,334 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton
size="sm"
color="primary"
class="mr-auto"
:to="{ name: 'admin-links' }"
>برگشت به صفحه قبل</CButton
>
<CButton
v-if="$route.params.details === 'new'"
size="sm"
color="success"
class="mr-1"
@click="post"
>افزودن
</CButton>
<CButton v-else size="sm" color="success" class="mr-1" @click="update"
>بروزرسانی</CButton
>
</CustomSubHeader>
<CRow style="display : flex ; flex-direction: column">
<CRow>
<CCol lg="6">
<CCard>
<CCardBody>
<CCol sm="12">
<h6>
قسمت انتخابی
<i
v-c-tooltip="
'شما باید تعیین کنید که این خبر برای کدام قسمت پرتال می باشد'
"
class="fas fa-question-circle"
></i>
</h6>
<el-select
:disabled="$auth.user.portals.length === 1 ? true: false"
v-model="links.modelType"
placeholder="انتخاب کنید"
style="width: 100%;"
>
<el-option
v-for="item in portals"
:key="item.value"
:label="item.name"
:value="item.value"
>
</el-option>
</el-select>
<p
style="margin-top : 5px !important ; color : red"
class="form-err"
v-if="validation.modelType"
>
{{ validation.modelType.msg }}
</p>
</CCol>
<el-divider></el-divider>
<CCol sm="12">
<CInput
:class="validation.title ? 'err' : null"
label="عنوان"
:description="
validation.title ? validation.title.msg : null
"
v-model="links.title"
/>
</CCol>
<el-divider></el-divider>
<CCol sm="12">
<CInput
:class="validation.url ? 'err' : null"
label="لینک"
:description="
validation.url ? validation.url.msg : null
"
v-model="links.url"
/>
</CCol>
<el-divider></el-divider>
<CCol sm="12">
<el-checkbox
v-model="links.showInHome"
label="نمایش در صفحه اصلی"
/>
</CCol>
<el-divider></el-divider>
<CCol sm="12">
<h6 class="mt-2">ترتیب نمایش</h6>
<!-- <el-input-number style="width:100%" class="mt-2" size="mini" v-model="links.index" controls-position="right" :min="0"></el-input-number>-->
<el-select style="width:100%" class="mt-2" v-model="links.index" placeholder="">
<el-option
v-for="item in allLinks.length + 10"
v-if="!allLinks.find((item2) => item2.index === item)"
:key="item"
:label="item"
:value="item">
</el-option>
</el-select>
</CCol>
</CCardBody>
</CCard>
</CCol>
<CCol lg="6">
<CCard>
<CCardBody>
<CCol sm="12">
<h5>آیکون</h5>
<el-divider />
<CCol>
<img
:src="links.icon"
style="width: 150px;"
alt=""
/>
</CCol>
<input type="file" ref="icon" @change="imagePreview" />
<p
style="margin-top : 5px !important ;"
class="form-err"
v-if="validation.icon"
>
{{ validation.icon.msg }}
</p>
<p class="mt-3 text-muted">
عکس 50*50 باشد. در غیر این صورت اتوماتیک بریده می شود.
</p>
</CCol>
</CCardBody>
</CCard>
</CCol>
</CRow>
</CRow>
</div>
</template>
<script>
import axiosUploadProcess from "@/mixins/axiosUploadProcess";
export default {
data() {
return {
links: null,
typePage: true,
validation: {},
editorConfig: {
language: "en",
extraPlugins: ["bidi", "justify"],
},
portals: null,
allLinks : null
};
},
mixins: [axiosUploadProcess],
computed: {
title() {
return this.$route.params.details === "new"
? "افزودن پیوند جدید"
: "مشاهده جزئیات پیوند";
},
},
methods: {
imagePreview(e) {
this.links.cover = URL.createObjectURL(e.target.files[0]);
},
post() {
this.validation = {};
const data = new FormData();
data.append("title", this.links.title.trim());
data.append("url", this.links.url);
data.append("index", this.links.index);
data.append("showInHome", this.links.showInHome);
data.append("modelType", this.links.modelType);
if (this.$refs.icon.files[0])
data.append("icon", this.$refs.icon.files[0]);
this.$axios
.post(`/api/admin/links`, data, this.axiosConfig)
.then((response) => {
this.$message({
type: "success",
message: "پیوند با موفقیت ایجاد شد.",
});
this.$router.push({
name: "admin-links",
});
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
if (err.response.status === 500) {
return this.$message({
type: "error",
message: "مشکلی در ارسال درخواست پیش آمده",
});
}
if (err.response.status === 422)
this.validation = err.response.data.validation;
else console.log(err.response.data);
});
},
update() {
this.validation = {};
const data = new FormData();
data.append("title", this.links.title.trim());
data.append("url", this.links.url);
data.append("index", this.links.index);
data.append("showInHome", this.links.showInHome);
data.append("modelType", this.links.modelType);
if (this.$refs.icon.files[0])
data.append("icon", this.$refs.icon.files[0]);
this.$axios
.put(`/api/admin/links/${this.links._id}`, data, this.axiosConfig)
.then((response) => {
this.$message({
type: "success",
message: "اطلاعات بروزرسانی شد.",
});
this.$nuxt.refresh();
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
if (err.response.status === 500) {
return this.$message({
type: "error",
message: "مشکلی در ارسال درخواست پیش آمده",
});
}
if (err.response.status === 422)
this.validation = err.response.data.validation;
else console.log(err.response.data);
});
},
},
head() {
return {
title: this.title,
};
},
layout: "admin",
async asyncData({ $axios, $auth, params, query, error }) {
try {
// const portals = await $axios.get("/api/admin/portals" , { progress: false });
// const allLinks = await $axios.get("/api/admin/links" , { progress: false });
const requests = [
$axios.get("/api/admin/links" , { progress: false }),
$axios.get(`/api/admin/portals` ,{ progress: false })
];
const fetch = await Promise.all(requests);
let [allLinks, portals] = fetch;
const setModelType = $auth.user.portals.length !== 1
? $auth.user.portals
: $auth.user.portals[0];
if (params.details !== "new") {
const links = await $axios.get(`/api/admin/links/${params.details}`);
return {
portals: portals.data,
allLinks : allLinks.data,
links: links.data
};
} else {
return {
portals: portals.data,
allLinks : allLinks.data,
links: {
title: '',
url: '',
index: null,
showInHome: true,
siteMap: true,
modelType: setModelType,
},
};
}
} catch (e) {
if (e?.response?.status === 401) {
error({
status: 401,
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (e?.response?.status === 403) {
error({
status: 403,
message: e?.response?.data?.message,
});
}
if (e?.response?.status === 500) {
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات پیش آمده",
});
} else
error({
status: 404,
message: "پیوند مورد نظر پیدا نشد",
});
}
},
};
</script>
+204
View File
@@ -0,0 +1,204 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="success" :to="{ name: 'admin-links-details', params: { details: 'new' } }"
class="mr-auto">افزودن</CButton>
</CustomSubHeader>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-filter"></i>
<span style="color:#000">فیلتر</span>
</slot>
</CCardHeader>
<CCardBody>
<CRow>
<CCol class="col">
<CRow>
<el-input v-model="search" size="medium" placeholder="جستجو" />
</CRow>
</CCol>
</CRow>
</CCardBody>
</CCard>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>{{ list_title }}</span>
</slot>
<slot> </slot>
</CCardHeader>
<CCardBody>
<el-table :data="filteredNewsFile" :default-sort="{ prop: 'date', order: 'descending' }" style="width: 100%">
<el-table-column type="index" label="#"> </el-table-column>
<el-table-column
label="آیکون پیوند"
width="">
<template slot-scope="scope">
<img :src="scope.row.icon || '/img/avatar.png'" :alt="scope.row.icon">
</template>
</el-table-column>
<el-table-column label="عنوان">
<template slot-scope="scope">
<a :href="scope.row.url" target="_blank">
<span style="height: 0px; display: ruby-base;">
{{ scope.row.title }}
</span>
</a>
</template>
</el-table-column>
<el-table-column label="نمایش در صفحه اصلی" width="">
<template slot-scope="scope">
<el-tag :type="scope.row.showInHome ? 'primary' : 'danger'">{{
scope.row.showInHome ? "بله" : "خیر"
}}</el-tag>
</template>
</el-table-column>
<el-table-column label="تاریخ ایجاد" width="">
<template slot-scope="scope">
<span>{{ jDate(scope.row.created_at) }}</span>
</template>
</el-table-column>
<el-table-column label="ویرایش" width="110" align="center">
<template slot-scope="scope">
<CButton color="danger" variant="outline" :key="scope.row._id + Math.random()"
@click="deleteNewsFile(scope.row._id)">
<i class="far fa-trash-alt"></i>
</CButton>
<CButton color="success" variant="outline" :key="scope.row._id" :to="{
name: 'admin-links-details',
params: { details: scope.row._id },
}">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
<CCard class="col" v-if="!search">
<CRow alignHorizontal="center" style="padding : 10px">
<el-pagination :hide-on-single-page="true" layout="prev, pager, next" :page-size="5"
:current-page.sync="curentPage" :total="links.length">
</el-pagination>
</CRow>
</CCard>
</div>
</template>
<script>
import moment from "moment-jalaali";
export default {
data() {
return {
title: "لیست پیوندها",
list_title: "لیست",
links: null,
search: "",
curentPage: 1,
skip: 0
};
},
computed: {
filteredNewsFile() {
if (this.search) {
return this.links.filter(
(data) =>
data.title.toLowerCase().includes(this.search.toLowerCase())
);
} else {
return this.links.slice((this.curentPage - 1) * 5, this.curentPage * 5);
}
},
},
methods: {
jDate(date) {
return moment(date).format("jYYYY/jMM/jDD");
},
deleteNewsFile(id) {
this.$confirm("پیوند حذف شود؟", "هشدار", {
confirmButtonText: "بله",
cancelButtonText: "لغو",
type: "warning",
})
.then(async () => {
this.$axios
.delete(`/api/admin/links/${id}`)
.then((res) => {
this.$message({
type: "success",
message: "پیوند با موفقیت حذف شد",
});
this.links = this.links.filter((item) => item._id !== id);
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
if (err.response.status === 422) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
console.log(err.response.data);
});
})
.catch(() => {
this.$message({
type: "warning",
message: "عملیات لغو شد",
});
});
},
},
head() {
return {
title: this.title,
};
},
layout: "admin",
async asyncData({
$axios,
error
}) {
try {
const links = await $axios.get(`/api/admin/links`);
return {
links: links.data,
};
} catch (e) {
if(e?.response?.status === 401){
error({
status: 401,
message: 'شما اجازه دسترسی به این صفحه را ندارید'
})
}else{
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات بوجود آمده است",
});
}
}
},
};
</script>
+172
View File
@@ -0,0 +1,172 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="primary" class="mr-auto" :to="{name: 'admin-meeting'}">برگشت به صفحه قبل</CButton>
<!-- <CButton size="sm" color="success" class="mr-1" @click="update">بروزرسانی</CButton>-->
</CustomSubHeader>
<CRow style="display : flex ; flex-direction: column">
<CRow>
<CCol lg="6">
<CCard>
<CCardBody>
<CCol sm="12">
<CInput disabled :class="validation.name ? 'err' : null" label="نام و نام خانوادگی" :description="
validation.name ? validation.name.msg : null
" v-model="meeting.name" />
</CCol>
<el-divider></el-divider>
<CCol sm="12">
<CInput disabled :class="validation.email ? 'err' : null" label="ایمیل" :description="
validation.email ? validation.email.msg : null
" v-model="meeting.email" />
</CCol>
<el-divider></el-divider>
<CCol sm="12">
<CInput disabled :class="validation.phoneNumber ? 'err' : null" label="شماره تلفن" :description="
validation.phoneNumber ? validation.phoneNumber.msg : null
" v-model="meeting.phoneNumber" />
</CCol>
<el-divider></el-divider>
<CCol sm="12">
<CInput disabled :class="validation.nationalCode ? 'err' : null" label="کد ملی" :description="
validation.nationalCode ? validation.nationalCode.msg : null
" v-model="meeting.nationalCode" />
</CCol>
</CCardBody>
</CCard>
</CCol>
<CCol lg="6">
<CCard>
<CCardBody>
<CCol sm="12">
<CInput disabled :class="validation.subject ? 'err' : null" label="موضوع" :description="
validation.subject ? validation.subject.msg : null
" v-model="meeting.subject" />
</CCol>
<el-divider></el-divider>
<CCol sm="12">
<CTextarea disabled :class="validation.description ? 'err' : null" label="متن پیام" :description="
validation.description ? validation.description.msg : null
" v-model="meeting.description" />
</CCol>
</CCardBody>
</CCard>
</CCol>
</CRow>
</CRow>
</div>
</template>
<script>
import unreadMeetingReq from "@/mixins/unreadMeetingReq"
export default {
data() {
return {
meeting: null,
validation: {}
};
},
mixins: [unreadMeetingReq],
computed: {
title() {
return "مشاهده جزئیات پیام";
},
},
methods: {
imagePreview(e) {
this.meeting.cover = URL.createObjectURL(e.target.files[0]);
},
update() {
this.validation = {};
const data = new FormData();
data.append("name", this.meeting.name.trim());
data.append("description", this.meeting.description.trim());
data.append("email", this.meeting.email);
data.append("allowShow", this.meeting.allowShow);
this.$axios
.put(`/api/admin/meeting/${this.$route.params.type}/${this.meeting._id}`, data, this.axiosConfig)
.then((response) => {
this.$message({
type: "success",
message: "اطلاعات بروزرسانی شد.",
});
this.$router.push({
name: "admin-meetings-type",
params : {type : this.$route.params.type}
});
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
if (err.response.status === 500) {
return this.$message({
type: "error",
message: "مشکلی در ارسال درخواست پیش آمده",
});
}
if (err.response.status === 422)
this.validation = err.response.data.validation;
else console.log(err.response.data);
});
},
},
head() {
return {
title: this.title,
};
},
layout: "admin",
async asyncData({
$axios,
$auth,
params,
query,
error
}) {
try {
const meeting = await $axios.get(`/api/admin/meeting/${params.details}`);
return {
meeting: meeting.data
};
} catch (e) {
if (e?.response?.status === 401) {
error({
status: 401,
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (e?.response?.status === 403) {
error({
status: 403,
message: e?.response?.data?.message,
});
}
if (e?.response?.status === 500) {
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات پیش آمده",
});
} else
error({
status: 404,
message: "پیام مورد نظر پیدا نشد",
});
}
},
};
</script>
+327
View File
@@ -0,0 +1,327 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
</CustomSubHeader>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-filter"></i>
<span style="color:#000">فیلتر</span>
</slot>
</CCardHeader>
<CCardBody>
<CRow>
<CCol md="6">
<CRow style="flex-direction : column;">
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>نام و نام خانوادگی</span>
</CCol>
<CCol col="md-9">
<el-input style="width : 100%" placeholder="" v-model="search.name"></el-input>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>ایمیل</span>
</CCol>
<CCol col="md-9">
<el-input style="width : 100%" placeholder="" v-model="search.email"></el-input>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>موضوع</span>
</CCol>
<CCol col="md-9">
<el-input style="width : 100%" placeholder="" v-model="search.terms"></el-input>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>تاریخ</span>
</CCol>
<CCol col="md-9">
<date-picker range clearable format="YYYY-MM-DD" display-format="jMMMM jD" v-model="search.date"></date-picker>
</CCol>
</CRow>
</CCol>
</CRow>
</CCol>
<CCol md="6">
<CRow style="flex-direction : column;">
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>وضعیت درخواست</span>
</CCol>
<CCol col="md-9">
<el-select v-model="search.read" clearable style="width : 100%">
<el-option :key="true" label="خوانده شده" :value="true">
</el-option>
<el-option :key="false" label="خوانده نشده" :value="false">
</el-option>
</el-select>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>شماره همراه</span>
</CCol>
<CCol col="md-9">
<el-input style="width : 100%" placeholder="" v-model="search.phoneNumber"></el-input>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>کد ملی</span>
</CCol>
<CCol col="md-9">
<el-input style="width : 100%" placeholder="" v-model="search.nationalCode"></el-input>
</CCol>
</CRow>
</CCol>
</CRow>
</CCol>
</CRow>
<CRow>
<el-button :loading="loading" @click="handleSearch" size="small" style="width: auto;margin: 25px auto auto auto;" type="primary"
icon="el-icon-search">
جست و جو</el-button>
</CRow>
</CCardBody>
</CCard>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>{{ list_title }}</span>
</slot>
<slot> </slot>
</CCardHeader>
<CCardBody>
<el-table v-loading="loading" :data="meeting.docs" :default-sort="{ prop: 'date', order: 'descending' }" style="width: 100%">
<el-table-column type="index" label="#"> </el-table-column>
<el-table-column label="نام و نام خانوادگی" width="">
<template slot-scope="scope">
<span>{{ scope.row.name }}</span>
</template>
</el-table-column>
<el-table-column label="ایمیل" width="">
<template slot-scope="scope">
<span>{{ scope.row.email }}</span>
</template>
</el-table-column>
<el-table-column label="وضعیت پیام" width="">
<template slot-scope="scope">
<el-tag :type="scope.row.read ? 'success' : 'danger'">
{{ scope.row.read ? 'خوانده شده' : 'خوانده نشده' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="تاریخ ایجاد" width="">
<template slot-scope="scope">
<span>{{ jDate(scope.row.created_at) }}</span>
</template>
</el-table-column>
<el-table-column label="ویرایش" width="110" align="center">
<template slot-scope="scope">
<CButton color="danger" variant="outline" :key="scope.row._id + Math.random()"
@click="deleteSlider(scope.row._id)">
<i class="far fa-trash-alt"></i>
</CButton>
<CButton color="success" variant="outline" :key="scope.row._id" :to="{
name: `admin-meeting-details`,
params: {details: scope.row._id },
}">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
<CCard class="col" v-if="meeting.totalDocs>5">
<CRow alignHorizontal="center" style="padding : 10px">
<el-pagination :hide-on-single-page="true" layout="prev, pager, next" :page-size="meeting.limit"
@current-change="handleCurrentChange" :current-page.sync="meeting.page" :total="meeting.totalDocs">
</el-pagination>
</CRow>
</CCard>
</div>
</template>
<script>
import moment from "moment-jalaali";
const _ = require('lodash');
export default {
data() {
return {
title: "لیست پیام",
list_title: "لیست",
meeting: null,
search: {},
loading : false
};
},
computed: {
pageQuery() {
return this.$route.query.page;
}
},
watch: {
pageQuery(newPage, oldPage) {
this.$nuxt.refresh();
}
},
methods: {
jDate(date) {
return moment(date).format("jYYYY/jMM/jDD");
},
openDialog(data) {
this.showNews = !this.showNews;
this.newsDetails = data;
},
handleCurrentChange(page) {
if (!_.isEmpty(this.search)) {
this.handleSearch(page);
} else {
this.$router.push({
name: "admin-meeting",
params : {type : this.$route.params},
query: {
page: page
}
});
}
},
handleSearch(page) {
this.loading = true;
const data = {
name: this.search.name,
email: this.search.email,
terms: this.search.terms,
phoneNumber: this.search.phoneNumber,
read: this.search.read,
nationalCode: this.search.nationalCode,
date: this.search.date
}
this.$axios.post(`/api/admin/meeting/search?page=${page}`, data, this.axiosConfig)
.then((result) => {
this.meeting = result.data;
this.loading = false;
})
.catch(err => {
this.loading = false;
if (err.response.status === 401) {
return this.$message({
type: 'error',
message: 'لطفا دوباره وارد سیستم شوید.'
})
}
if (err.response.status === 422) this.validation = err.response.data.validation
else console.log(err.response.data)
})
},
deleteSlider(id) {
this.$confirm("پیام حذف شود؟", "هشدار", {
confirmButtonText: "بله",
cancelButtonText: "لغو",
type: "warning",
})
.then(async () => {
this.$axios
.delete(`/api/admin/meeting/${id}`)
.then((res) => {
this.$message({
type: "success",
message: "پیام با موفقیت حذف شد",
});
this.$nuxt.refresh();
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
if (err.response.status === 422) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
console.log(err.response.data);
});
})
.catch(() => {
this.$message({
type: "warning",
message: "عملیات لغو شد",
});
});
},
},
head() {
return {
title: this.title,
};
},
layout: "admin",
async asyncData({
$axios,
params,
query,
error
}) {
try {
const meeting = await $axios.get(`/api/admin/meeting?page=${query.page}`);
return {
meeting: meeting.data,
};
} catch (e) {
if(e?.response?.status === 401){
error({
status: 401,
message: 'شما اجازه دسترسی به این صفحه را ندارید'
})
}else{
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات بوجود آمده است",
});
}
}
},
};
</script>
+794
View File
@@ -0,0 +1,794 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="primary" class="mr-auto" :to="{ name: 'admin-news' }">برگشت به صفحه قبل</CButton>
<CButton v-if="$route.params.details === 'new'" size="sm" color="success" class="mr-1" @click="post">افزودن
</CButton>
<CButton v-else size="sm" color="success" class="mr-1" @click="update">بروزرسانی</CButton>
</CustomSubHeader>
<CRow>
<CCol lg="6">
<!-- *************** start set category *************** -->
<CCard>
<CCardBody>
<CForm>
<CRow>
<CCol>
<h6>
قسمت انتخابی
<i v-c-tooltip="'شما باید تعیین کنید که این خبر برای کدام قسمت پرتال می باشد'"
class="fas fa-question-circle"></i>
</h6>
<el-select
:disabled="$auth.user.portals.length === 1"
v-model="news.modelType"
placeholder="انتخاب کنید"
style="width: 100%;"
@change="[clearIDs('catId'),clearIDs('newsFile')]"
>
<el-option
v-for="item in portals"
:key="item.value"
:label="item.name"
:value="item.value"
>
</el-option>
</el-select>
<p
style="margin-top : 5px !important ; color : red"
class="form-err"
v-if="validation.modelType"
>
{{ validation.modelType.msg }}
</p>
<template v-if="filterParent">
<el-divider/>
<CRow>
<CCol sm="12">
<h6>
{{
this.$route.params.details !== "new"
? "دسته بندی"
: "انتخاب دسته بندی"
}}
</h6>
<el-select
filterable
clearable
style="width : 100%"
v-model="catId"
placeholder="انتخاب دسته بندی"
@change="clearIDs('newsFile')"
>
<el-option
v-for="item in filterParent"
:key="item._id"
:label="item.title"
:value="item._id"
>
<!-- <span>{{setTitle(item)}}</span> -->
</el-option>
</el-select>
<p
style="margin-top : 5px !important ; color : red"
class="form-err"
v-if="validation.catId"
>
{{ validation.catId.msg }}
</p>
</CCol>
</CRow>
</template>
</CCol>
</CRow>
</CForm>
</CCardBody>
</CCard>
<!-- *************** end set category ***************** -->
<!-- *************** start set details **************** -->
<CCard>
<CCardBody>
<CRow>
<CCol sm="12">
<CTextarea
:class="validation.summaryTitle ? 'err' : null"
label="رو تیتر"
:description="validation.summaryTitle? validation.summaryTitle.msg: null "
v-model="news.summaryTitle"
rows="3"
/>
</CCol>
</CRow>
<CRow>
<CCol sm="12">
<CTextarea
:class="validation.title ? 'err' : null"
label="تیتر"
:description="validation.title ? validation.title.msg : null"
v-model="news.title"
rows="3"
/>
</CCol>
</CRow>
<CRow>
<CCol sm="12">
<CTextarea
:class="validation.leadTitle ? 'err' : null"
label="لید"
:description="validation.leadTitle? validation.leadTitle.msg: null "
v-model="news.leadTitle"
rows="3"
/>
</CCol>
</CRow>
<CRow>
<CCol sm="12">
<CTextarea
:class="validation.metaTagDesc ? 'err' : null"
label="توضیحات برای موتورهای جست و جو"
placeholder="در صورتی که این کادر را خالی بگذارید از متن لید استفاده خواهد شد."
:description="validation.metaTagDesc? validation.metaTagDesc.msg: null"
v-model="news.metaTagDesc"
rows="3"
/>
</CCol>
</CRow>
<CRow>
<CCol sm="12">
<p>کلمات کلیدی</p>
<div>
<el-input
class="input-new-tag mb-3"
v-if="inputVisible"
v-model="inputValue"
ref="saveTagInput"
size="small"
@keyup.enter.native="handleInputConfirm"
@blur="handleInputConfirm"
>
</el-input>
<el-button
v-else
class="button-new-tag mb-3"
size="small"
@click="showInput"
>کلمه جدید
</el-button
>
</div>
<div class="mb-3">
<el-tag
class="ml-1"
:key="tag"
v-for="tag in news.keywords"
closable
:disable-transitions="false"
@close="handleClose(tag)"
>
{{ tag }}
</el-tag>
</div>
</CCol>
</CRow>
<CRow>
<CCol>
<CRow>
<CCol sm="12" class="mb-3">
<template>
<client-only>
<p>متن خبر</p>
<ckeditor
v-model="news.pageContent"
:config="editorConfig"
></ckeditor>
<p class="text-danger" v-if="validation.pageContent">
{{ validation.pageContent.msg }}
</p>
</client-only>
</template>
</CCol>
</CRow>
</CCol>
</CRow>
</CCardBody>
</CCard>
<!-- *************** end set details ****************** -->
</CCol>
<CCol lg="6">
<CCard>
<CCardBody>
<CCol sm="12">
<el-checkbox
v-model="news.publish"
label="انتشار خبر"
/>
</CCol>
<CCol sm="12">
<el-checkbox
v-model="news.showInHome"
label="نمایش خبر در صفحه اصلی"
/>
</CCol>
<el-divider></el-divider>
<!-- <CCol sm="12">
<el-checkbox
v-model="news.slider"
label="قرار گرفتن خبر در اسلایدر صفحه اصلی"
/>
</CCol> -->
<!-- <el-divider></el-divider> -->
<CCol sm="12">
<el-checkbox
v-model="news.priority"
label="نمایش خبر در بالای صفحه ی دسته بندی"
/>
</CCol>
<CCol sm="12">
<el-checkbox
v-model="news.allowComment"
label="اجازه کامنت گذاشتن برای این خبر"
/>
</CCol>
<el-divider></el-divider>
<CCol sm="12">
<el-checkbox
v-model="news.special"
label="نمایش در قسمت مطالب ویژه"
/>
</CCol>
<CCol sm="12">
<el-checkbox
v-model="news.notifications"
label="قرار گرفتن در بخش اطلاعیه ها"
/>
</CCol>
</CCardBody>
</CCard>
<CCard>
<CCardBody>
<CCol sm="12">
<h6>
انتخاب موضوع پرونده خبری
<i
v-c-tooltip="
'شما می توانید در صورت تمایل این خبر را در یکی از موضوعات پرونده های خبری قرار دهید'
"
class="fas fa-question-circle"
></i>
</h6>
<el-select
v-model="news.newsFileId"
placeholder="انتخاب کنید"
style="width: 100%;"
filterable
clearable
>
<el-option
v-for="item in filteredSetNewsFile"
:key="item._id"
:label="item.title"
:value="item._id"
>
</el-option>
</el-select>
<p
style="margin-top : 5px !important ; color : red"
class="form-err"
v-if="validation.newsFileId"
>
{{ validation.newsFileId.msg }}
</p>
</CCol>
</CCardBody>
</CCard>
<CCard v-if="$route.params.details !=='new'">
<CCardBody>
<CCol sm="12">
<h6>
تغییر زمان ثبت خبر
</h6>
<date-picker clearable input-format="YYYY-MM-DD HH:mm" format="YYYY-MM-DD HH:mm" display-format="jYYYY/jMM/jDD HH:mm"
v-model="news.customDate" type="datetime"/>
<p
style="margin-top : 5px !important ; color : red"
class="form-err"
v-if="validation.customDate"
>
{{ validation.customDate.msg }}
</p>
</CCol>
</CCardBody>
</CCard>
<CCard>
<CCardBody>
<p style="font-weight: bold; color: red;">*در صورتی که عکس خبر وارد نشده باشد خبر در حالت ناقص قرار می گیرد</p>
<CCol sm="12">
<h4>عکس خبر هنگام نمایش در لیست اخبار</h4>
<el-divider/>
<CCol>
<img :src="news.thumbCover" style="width: 100%;" alt=""/>
</CCol>
<input type="file" ref="thumbCover" @change="imagePreview2"/>
<p style="margin-top: 5px !important;" class="form-err text-danger" v-if="validation.thumbCover">
{{ validation.thumbCover.msg }}</p>
<p class="mt-3 text-muted">
عکس 300*600 باشد. در غیر این صورت اتوماتیک بریده می شود.
</p>
</CCol>
<CCol sm="12">
<h4>کاور اصلی خبر</h4>
<el-divider/>
<CCol>
<img :src="news.cover" style="width: 100%;" alt=""/>
</CCol>
<input type="file" ref="cover" @change="imagePreview"/>
<p style="margin-top: 5px !important;" class="form-err text-danger" v-if="validation.cover">
{{ validation.cover.msg }}</p>
<p class="mt-3 text-muted">
عکس 1080*1920 باشد. در غیر این صورت اتوماتیک بریده می شود.
</p>
</CCol>
</CCardBody>
</CCard>
</CCol>
<CCol sm="12" v-if="$route.params.details !== 'new'">
<CCard>
<CCardBody>
<CRow>
<CCol sm="6">
<h2>لیست فایل های ضمیمه</h2>
<el-divider></el-divider>
<el-table :data="news.attachments">
<el-table-column
type="index"
label="#"
>
</el-table-column>
<el-table-column
label="فایل"
width=""
>
<template slot-scope="scope">
<a :href="scope.row.file" target="_blank">{{ scope.row.title }}</a>
</template>
</el-table-column>
<el-table-column
label="ویرایش"
width="75"
align="center"
>
<template slot-scope="scope">
<CButton color="danger" variant="outline" @click="deleteFile(scope.row._id)">
<i class="far fa-trash-alt"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCol>
<CCol sm="6">
<h2>افزودن فایل ضمیمه</h2>
<el-divider></el-divider>
<input type="file" ref="attFile"/>
<p class="text-danger" v-if="validation.file">{{ validation.file.msg }}</p>
<br>
<br>
<input type="text" ref="attTitle" placeholder="عنوان فایل را بنویسید" style="width: 300px;"/>
<p class="text-danger" v-if="validation.attTitle">{{ validation.attTitle.msg }}</p>
<br>
<br>
<el-button size="small" type="success" @click="addFile">افزودن</el-button>
</CCol>
</CRow>
</CCardBody>
</CCard>
</CCol>
</CRow>
</div>
</template>
<script>
import axiosUploadProcess from "@/mixins/axiosUploadProcess"
import moment from "moment-jalaali";
export default {
data() {
return {
news: null,
typePage: true,
inputVisible: false,
inputValue: "",
validation: {},
newsFile: [],
editorConfig: {
language: "en",
extraPlugins: ["bidi", "justify"],
versionCheck:false
},
parents: null,
portals: null
}
},
mixins: [axiosUploadProcess],
computed: {
title() {
return this.$route.params.details === "new"
? "افزودن خبر جدید"
: "مشاهده جزئیات خبر";
},
catId: {
get() {
if (this.$route.params.details === 'new') return this.news.catId
else return this.news.catId._id
},
set(value) {
if (this.$route.params.details === 'new') this.news.catId = value
else this.news.catId._id = value
}
},
filterParent() {
return this.parents.filter(item => item.modelType === this.news.modelType)
},
filteredSetNewsFile() {
return this.newsFile.filter(item => item.modelType === this.news.modelType && (this.$route.params.details === 'new' ? item.catId === this.news.catId : item.catId === this.news.catId._id))
}
},
methods: {
jDate(date) {
return moment(date);
},
handleClose(tag) {
this.news.keywords.splice(this.news.keywords.indexOf(tag), 1);
},
showInput() {
this.inputVisible = true;
this.$nextTick((_) => {
this.$refs.saveTagInput.$refs.input.focus();
});
},
handleInputConfirm() {
let inputValue = this.inputValue;
if (inputValue) {
this.news.keywords.push(inputValue);
}
this.inputVisible = false;
this.inputValue = "";
},
clearIDs(mode) {
if (mode === 'catId') this.catId = ''
if (mode === 'newsFile') this.news.newsFileId = ''
},
imagePreview(e) {
this.news.cover = URL.createObjectURL(e.target.files[0]);
},
imagePreview2(e) {
this.news.thumbCover = URL.createObjectURL(e.target.files[0]);
},
post() {
this.validation = {};
const data = new FormData();
data.append("title", this.news?.title?.trim());
data.append("summaryTitle", this.news?.summaryTitle?.trim());
data.append("leadTitle", this.news?.leadTitle?.trim());
data.append("catId", this.catId);
data.append("priority", this.news.priority);
data.append("allowComment", this.news.allowComment);
data.append("showInHome", this.news.showInHome);
// data.append("slider", this.news.slider);
data.append("publish", this.news.publish);
data.append("pageContent", this.news.pageContent);
data.append("special", this.news.special);
data.append("notifications", this.news.notifications);
data.append("keywords", JSON.stringify(this.news.keywords));
data.append("metaTagDesc", this.news?.metaTagDesc || this.news?.leadTitle);
data.append("modelType", this.news.modelType);
if (this.news.newsFileId) {
data.append("newsFileId", this.news.newsFileId);
}
if (this.$refs.cover.files[0]) data.append("cover", this.$refs.cover.files[0]);
if (this.$refs.thumbCover.files[0]) data.append("thumbCover", this.$refs.thumbCover.files[0]);
this.$axios
.post(`/api/admin/news`, data, this.axiosConfig)
.then((response) => {
this.$message({
type: "success",
message: "خبر با موفقیت ایجاد شد.",
});
this.$router.push({
name: "admin-news",
});
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
if (err.response.status === 500) {
return this.$message({
type: "error",
message: "مشکلی در ارسال درخواست پیش آمده",
});
}
if (err.response.status === 422) {
this.validation = err.response.data.validation;
this.$message({
type: 'warning',
message: 'پارامتر هارو بررسی کنید'
})
} else console.log(err.response.data);
});
},
update() {
this.validation = {};
const data = new FormData();
data.append("title", this.news.title.trim());
data.append("summaryTitle", this.news.summaryTitle.trim());
data.append("leadTitle", this.news.leadTitle.trim());
data.append("catId", this.catId);
data.append("priority", this.news.priority);
data.append("allowComment", this.news.allowComment);
data.append("showInHome", this.news.showInHome);
// data.append("slider", this.news.slider);
data.append("publish", this.news.publish);
data.append("pageContent", this.news.pageContent);
data.append("special", this.news.special);
data.append("notifications", this.news.notifications);
data.append("keywords", JSON.stringify(this.news.keywords));
data.append("metaTagDesc", this.news.metaTagDesc || this.news.leadTitle);
data.append("modelType", this.news.modelType);
data.append("customDate", this.news.customDate);
if (this.news.newsFileId) {
data.append("newsFileId", this.news.newsFileId);
}
if (this.$refs.cover.files[0]) data.append("cover", this.$refs.cover.files[0]);
if (this.$refs.thumbCover.files[0]) data.append("thumbCover", this.$refs.thumbCover.files[0]);
this.$axios
.put(`/api/admin/news/${this.news._id}`, data, this.axiosConfig)
.then((response) => {
this.$message({
type: "success",
message: "اطلاعات بروزرسانی شد.",
});
this.$nuxt.refresh();
this.$refs.cover.value = null
this.$refs.thumbCover.value = null
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
if (err.response.status === 500) {
return this.$message({
type: "error",
message: "مشکلی در ارسال درخواست پیش آمده",
});
}
if (err.response.status === 422) {
this.$message({
type: 'warning',
message: 'پارامترها رو بررسی کنید'
})
this.validation = err.response.data.validation;
} else console.log(err.response.data);
});
},
addFile() {
this.validation = {}
const data = new FormData()
data.append('file', this.$refs.attFile.files[0])
data.append('attTitle', this.$refs.attTitle.value)
this.$axios.post(`/api/admin/news/attachments/${this.news._id}`, data, this.axiosConfig)
.then(res => {
this.$message({
type: 'success',
message: 'فایل با موفقیت اضافه شد'
})
this.$refs.attFile.value = null
this.$refs.attTitle.value = null
this.$nuxt.refresh()
})
.catch(err => {
if (err.response.status === 401) {
return this.$message({
type: 'error',
message: 'لطفا دوباره وارد سیستم شوید.'
})
}
if (err.response.status === 403) {
return this.$message({
type: 'error',
message: err.response.data.message
})
}
if (err.response.status === 500) {
return this.$message({
type: 'error',
message: 'مشکلی در ارسال درخواست پیش آمده'
})
}
if (err.response.status === 422) {
this.$message({
type: 'warning',
message: 'پارامترها را بررسی کنید'
})
this.validation = err.response.data.validation
} else console.log(err.response.data);
})
},
deleteFile(id) {
this.$confirm('فایل حذف شود؟', 'هشدار', {
confirmButtonText: 'بله',
cancelButtonText: 'لغو',
type: 'warning'
})
.then(async () => {
this.$axios.delete(`/api/admin/news/attachments/${id}`)
.then(res => {
this.$message({
type: 'success',
message: 'فایل با موفقیت حذف شد'
})
this.news.attachments = this.news.attachments.filter(item => item._id !== id)
})
.catch(err => {
if (err.response.status === 401) {
return this.$message({
type: 'error',
message: 'لطفا دوباره وارد سیستم شوید.'
})
}
if (err.response.status === 403) {
return this.$message({
type: 'error',
message: err.response.data.message
})
}
if (err.response.status === 422) {
return this.$message({
type: 'error',
message: err.response.data.message
})
}
console.log(err.response.data)
})
})
.catch(() => {
this.$message({
type: 'warning',
message: 'عملیات لغو شد'
})
})
}
},
head() {
return {
title: this.title,
};
},
layout: "admin",
async asyncData({$axios, $auth, params, query, error}) {
try {
const requests = [
$axios.get("/api/admin/category/getParent", {
params: {
type: "news",
},
}),
$axios.get("/api/admin/portals", {progress: false}),
$axios.get(`/api/admin/newsFile`, {progress: false})
];
const fetch = await Promise.all(requests);
let [parents, portals, newsFile] = fetch;
const setModelType = $auth.user.portals.length !== 1 ? $auth.user.portals : $auth.user.portals[0];
// const setFilterParent =
// $auth.user.portals.length !== 1
// ? null
// : parents.data.filter(
// (item) => item.modelType === $auth.user.portals[0]
// );
if (params.details !== "new") {
const news = await $axios.get(`/api/admin/news/${params.details}`);
return {
portals: portals.data,
parents: parents.data,
news: news.data,
// filterParent: parents.data,
newsFile: newsFile.data
};
} else {
return {
portals: portals.data,
parents: parents.data,
// filterParent: parents.data,
newsFile: newsFile.data,
news: {
title: '',
summaryTitle: '',
leadTitle: '',
catId: $auth.user.specialPermissions,
allowComment: false,
// slider: false,
priority: false,
showInHome: true,
siteMap: true,
special: false,
publish: true,
notifications: false,
pageContent: '',
keywords: [],
metaTagDesc: '',
newsStatus: false,
modelType: setModelType,
newsFileId: ''
},
};
}
} catch (e) {
console.log(e)
if (e?.response?.status === 401) {
error({
status: 401,
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (e?.response?.status === 403) {
error({
status: 403,
message: e?.response?.data?.message,
});
}
if (e?.response?.status === 500) {
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات پیش آمده",
});
} else
error({
status: 404,
message: "خبر مورد نظر پیدا نشد",
});
}
},
};
</script>
+490
View File
@@ -0,0 +1,490 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="success" :to="{ name: 'admin-news-details', params: { details: 'new' } }"
class="mr-auto">افزودن
</CButton>
</CustomSubHeader>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-filter"></i>
<span style="color:#000">فیلتر</span>
</slot>
</CCardHeader>
<CCardBody>
<CRow>
<CCol md="6">
<CRow style="flex-direction : column;">
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>تیتر</span>
</CCol>
<CCol col="md-9">
<el-input style="width : 100%" placeholder="" v-model="search.term"></el-input>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>دسته بندی</span>
</CCol>
<CCol col="md-9">
<el-select filterable clearable style="width : 100%" v-model="search.catId"
placeholder="انتخاب دسته بندی">
<el-option v-for="item in parents" :key="item._id" :label="item.title" :value="item._id">
<!-- <span>{{setTitle(item)}}</span> -->
</el-option>
</el-select>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>پرونده خبری</span>
</CCol>
<CCol col="md-9">
<el-select filterable clearable style="width : 100%" v-model="search.newsFile">
<el-option v-for="item in newsFile" :key="item._id" :label="item.title" :value="item._id">
<!-- <span>{{setTitle(item)}}</span> -->
</el-option>
</el-select>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>وضعیت انتشار</span>
</CCol>
<CCol col="md-9">
<el-select v-model="search.publish" clearable style="width : 100%">
<el-option :key="true" label="منتشر شده" :value="true">
</el-option>
<el-option :key="false" label="منتشر نشده" :value="false">
</el-option>
</el-select>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>تاریخ</span>
</CCol>
<CCol col="md-9">
<date-picker range clearable format="YYYY-MM-DD" display-format="jMMMM jD"
v-model="search.date"></date-picker>
</CCol>
</CRow>
</CCol>
</CRow>
</CCol>
<CCol md="6">
<CRow style="flex-direction : column;">
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>قسمت</span>
</CCol>
<CCol col="md-9">
<el-select v-model="search.portals" clearable style="width : 100%">
<el-option v-for="item in portals" :key="item.value" :label="item.name" :value="item.value">
</el-option>
</el-select>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>وضعیت خبر</span>
</CCol>
<CCol col="md-9">
<el-select v-model="search.status" clearable style="width : 100%">
<el-option :key="true" label="کامل" :value="true">
</el-option>
<el-option :key="false" label="ناقص" :value="false">
</el-option>
</el-select>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>اطلاعیه ها</span>
</CCol>
<CCol col="md-9">
<el-select v-model="search.notifications" clearable style="width : 100%">
<el-option :key="true" label="بله" :value="true">
</el-option>
<el-option :key="false" label="خیر" :value="false">
</el-option>
</el-select>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>مطالب ویژه</span>
</CCol>
<CCol col="md-9">
<el-select v-model="search.special" clearable style="width : 100%">
<el-option :key="true" label="بله" :value="true">
</el-option>
<el-option :key="false" label="خیر" :value="false">
</el-option>
</el-select>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3" v-if="$auth.user.permissions.includes('superAdmin')">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>نمایش در صفحه اصلی</span>
</CCol>
<CCol col="md-9">
<el-select v-model="search.showInHome" clearable style="width : 100%">
<el-option :key="true" label="بله" :value="true">
</el-option>
<el-option :key="false" label="خیر" :value="false">
</el-option>
</el-select>
</CCol>
</CRow>
</CCol>
</CRow>
</CCol>
</CRow>
<CRow>
<el-button :loading="loading" @click="handleSearch" size="small"
style="width: auto;margin: 25px auto auto auto;" type="primary"
icon="el-icon-search">
جست و جو
</el-button>
</CRow>
</CCardBody>
</CCard>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>{{ list_title }}</span>
</slot>
<slot></slot>
</CCardHeader>
<CCardBody>
<el-table v-loading="loading" :data="news.docs" :default-sort="{ prop: 'date', order: 'descending' }"
style="width: 100%">
<el-table-column type="index" label="#" :index="1"></el-table-column>
<!-- <el-table-column
label="کاور خبر"
width="200">
<template slot-scope="scope">
<img :src="scope.row.cover || '/img/avatar.png'" style="width: 200px;" :alt="scope.row.title">
</template>
</el-table-column> -->
<el-table-column label="تیتر" width="180px">
<template slot-scope="scope">
<span class="title">
<el-popover placement="top-end" trigger="hover" :content="scope.row.title">
<i class="el-icon-info" slot="reference"></i>
</el-popover>
{{ scope.row.title }}
</span>
</template>
</el-table-column>
<el-table-column label="نویسنده">
<template slot-scope="scope">
<span v-if="!$auth.user.permissions.includes('superAdmin')">{{
scope.row._creator.firstName + " " + scope.row._creator.lastName
}}</span>
<nuxt-link v-else :to="{
name: 'admin-users-profile',
params: { profile: scope.row._creator._id },
}"><span style="color: blue;">{{
scope.row._creator.firstName +
" " +
scope.row._creator.lastName
}}</span></nuxt-link>
</template>
</el-table-column>
<el-table-column prop="catId.title" label="دسته بندی" width="">
<!-- <template slot-scope="scope">-->
<!-- <span>{{ scope.row.catId.title }}</span>-->
<!-- </template>-->
</el-table-column>
<el-table-column label="وضعیت خبر" width="">
<template slot-scope="scope">
<el-tag :type="scope.row.newsStatus ? 'success' : 'danger'">{{
scope.row.newsStatus ? "کامل" : "ناقص"
}}
</el-tag>
</template>
</el-table-column>
<el-table-column label="وضعیت انتشار" width="">
<template slot-scope="scope">
<el-tag :type="scope.row.publish ? 'primary' : 'danger'">{{
scope.row.publish ? "منتشر شده" : "منتشر نشده"
}}
</el-tag>
</template>
</el-table-column>
<el-table-column v-if="$auth.user.permissions.includes('superAdmin')" label="نمایش در صفحه اصلی" width="">
<template slot-scope="scope">
<el-tag :type="scope.row.showInHome ? 'primary' : 'danger'">{{
scope.row.showInHome ? "بله" : "خیر"
}}
</el-tag>
</template>
</el-table-column>
<el-table-column label="بخش" width="">
<template slot-scope="scope">
<el-tag :type="'primary'">{{ getModelName(scope.row.modelType) }}</el-tag>
</template>
</el-table-column>
<el-table-column label="تعداد بازدید" width="">
<template slot-scope="scope">
<span>{{scope.row.userViews}}</span>
</template>
</el-table-column>
<el-table-column label="تاریخ ایجاد" width="">
<template slot-scope="scope">
<span>{{ jDate(scope.row.created_at) }}</span>
</template>
</el-table-column>
<el-table-column label="ویرایش" width="110" align="center">
<template slot-scope="scope">
<CButton color="danger" variant="outline" :key="scope.row._id + Math.random()"
@click="deleteNews(scope.row._id)">
<i class="far fa-trash-alt"></i>
</CButton>
<CButton color="success" variant="outline" :key="scope.row._id" :to="{
name: 'admin-news-details',
params: { details: scope.row._id },
}">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
<CCard class="col" v-if="news.totalDocs>5">
<CRow alignHorizontal="center" style="padding : 10px">
<el-pagination
:hide-on-single-page="true"
layout="prev, pager, next"
:page-size="news.limit"
@current-change="handleCurrentChange"
:current-page.sync="news.page"
:total="news.totalDocs"
>
</el-pagination>
</CRow>
</CCard>
</div>
</template>
<script>
import moment from "moment-jalaali";
const _ = require('lodash');
export default {
data() {
return {
title: "لیست اخبار",
list_title: "لیست",
portals: [],
filterParent: null,
news: null,
search: {},
newsFile: [],
loading: false
};
},
computed: {
pageQuery() {
return this.$route.query.page;
}
},
watch: {
pageQuery(newPage, oldPage) {
this.$nuxt.refresh();
}
},
methods: {
getModelName(value) {
/** get name of portal */
// for (const item of news.data.docs) {
// item.modelType = portals.data.filter((value) => value.value === item.modelType)[0].name;
// }
return this.portals.find(item => item.value === value).name
},
jDate(date) {
return moment(date).format("jYYYY/jMM/jDD");
},
handleCurrentChange(page) {
if (!_.isEmpty(this.search)) {
this.handleSearch(page);
} else {
this.$router.push({
name: "admin-news",
query: {
page: page
}
});
}
},
handleSearch(page) {
this.loading = true;
const data = {
term: this.search.term,
catId: this.search.catId,
status: this.search.status,
showInHome: this.search.showInHome,
portals: this.search.portals,
publish: this.search.publish,
notifications: this.search.notifications,
special: this.search.special,
newsFile: this.search.newsFile,
date: this.search.date,
}
this.$axios.post(`/api/admin/news/search?page=${page}`, data, this.axiosConfig)
.then((result) => {
/** get name of portal */
// for (const item of result.data.docs) {
// item.modelType = this.portals.filter((value) => value.value === item.modelType)[0].name;
// }
this.news = result.data;
this.loading = false;
})
.catch(err => {
this.loading = false;
if (err.response.status === 401) {
return this.$message({
type: 'error',
message: 'لطفا دوباره وارد سیستم شوید.'
})
}
if (err.response.status === 422) this.validation = err.response.data.validation
else console.log(err.response.data)
})
},
deleteNews(id) {
this.$confirm("خبر حذف شود؟", "هشدار", {
confirmButtonText: "بله",
cancelButtonText: "لغو",
type: "warning",
})
.then(async () => {
this.$axios
.delete(`/api/admin/news/${id}`)
.then((res) => {
this.$message({
type: "success",
message: "خبر با موفقیت حذف شد",
});
this.$nuxt.refresh();
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
if (err.response.status === 422) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
console.log(err.response.data);
});
})
.catch(() => {
this.$message({
type: "warning",
message: "عملیات لغو شد",
});
});
},
},
head() {
return {
title: this.title,
};
},
layout: "admin",
async asyncData({$axios, query, error}) {
try {
const requests = [
$axios.get(`/api/admin/news?page=${query.page}`, { progress: false }),
$axios.get(`/api/admin/portals` ,{ progress: false }),
$axios.get("/api/admin/newsFile" ,{ progress: false }),
$axios.get("/api/admin/category/getParent", {
params: {
type: "news",
},
})
];
const fetch = await Promise.all(requests);
let [news, portals, newsFile , parents] = fetch;
return {
portals: portals.data,
parents: parents.data,
news: news.data,
newsFile: newsFile.data
};
} catch (e) {
console.log(e);
if (e?.response?.status === 401) {
error({
status: 401,
message: 'شما اجازه دسترسی به این صفحه را ندارید'
})
} else {
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات بوجود آمده است",
});
}
}
}
};
</script>
+378
View File
@@ -0,0 +1,378 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="primary" class="mr-auto" :to="{ name: 'admin-newsFile' }">برگشت به صفحه قبل</CButton>
<CButton v-if="$route.params.details === 'new'" size="sm" color="success" class="mr-1" @click="post">افزودن</CButton>
<CButton v-else size="sm" color="success" class="mr-1" @click="update">بروزرسانی</CButton>
</CustomSubHeader>
<CRow style="display : flex ; flex-direction: column">
<CRow>
<CCol lg="6">
<CCard>
<CCardBody>
<CRow>
<CCol sm="12">
<CInput
:class="validation.title ? 'err' : null"
label="عنوان"
:description="
validation.title ? validation.title.msg : null"
v-model="newsFile.title"
/>
</CCol>
<el-divider></el-divider>
<CCol sm="12">
<CTextarea
:class="validation.description ? 'err' : null"
label="توضیحات"
:description="
validation.description ? validation.description.msg : null"
v-model="newsFile.description"
/>
</CCol>
</CRow>
</CCardBody>
</CCard>
</CCol>
<CCol lg="6">
<CCard>
<CCardBody>
<CCol sm="12">
<h6>
قسمت انتخابی
<i v-c-tooltip="'شما باید تعیین کنید که این خبر برای کدام قسمت پرتال می باشد'" class="fas fa-question-circle"></i>
</h6>
<el-select
:disabled="$auth.user.portals.length === 1"
v-model="newsFile.modelType"
placeholder="انتخاب کنید"
@change="changePortalVal"
style="width: 100%;">
<el-option
v-for="item in portals"
:key="item.value"
:label="item.name"
:value="item.value">
</el-option>
</el-select>
<p style="margin-top : 5px !important ; color : red" class="form-err" v-if="validation.modelType">{{ validation.modelType.msg }}</p>
</CCol>
<el-divider></el-divider>
<template v-if="newsFile.modelType">
<CCol sm="12">
<h6>
{{
this.$route.params.details !== "new"
? "دسته بندی"
: "انتخاب دسته بندی"
}}
</h6>
<el-select
filterable
clearable
style="width : 100%"
v-model="catId"
placeholder="انتخاب دسته بندی">
<el-option
v-for="item in filterParent"
v-if="availableCategory(item._id)"
:key="item._id"
:label="item.title"
:value="item._id"
>
<!-- <span>{{setTitle(item)}}</span> -->
</el-option>
</el-select>
<p style="margin-top : 5px !important ; color : red" class="form-err" v-if="validation.catId">
{{ validation.catId.msg }}
</p>
</CCol>
<el-divider></el-divider>
</template>
<CCol sm="12">
<el-checkbox
v-model="newsFile.showInHome"
label="نمایش در صفحه اصلی"
/>
</CCol>
<CCol sm="12" v-if="catId">
<h6 class="mt-2">ترتیب نمایش</h6>
<!-- <el-input-number style="width:100%" class="mt-2" size="mini" v-model="slider.index"-->
<!-- controls-position="right" :min="0"></el-input-number>-->
<el-select style="width:100%" class="mt-2" v-model="newsFile.index" placeholder="">
<el-option
v-for="item in tempAllNewsFile.length + 10"
v-if="!tempAllNewsFile.find((item2) => item2.index === item)"
:key="item"
:label="item"
:value="item">
</el-option>
</el-select>
</CCol>
</CCardBody>
</CCard>
</CCol>
<CCol lg="6">
<CCard>
<CCardBody>
<h4>کاور اصلی خبر</h4>
<el-divider/>
<CCol>
<img :src="newsFile.cover" style="width: 100%;" alt=""/>
</CCol>
<input type="file" ref="cover" @change="imagePreview"/>
<p style="margin-top: 5px !important;" class="form-err text-danger" v-if="validation.cover">
{{ validation.cover.msg }}</p>
<p class="mt-3 text-muted">
عکس 300*600 باشد. در غیر این صورت اتوماتیک بریده می شود.
</p>
</CCardBody>
</CCard>
</CCol>
</CRow>
</CRow>
</div>
</template>
<script>
import axiosUploadProcess from "@/mixins/axiosUploadProcess"
export default {
data() {
return {
newsFile: null,
typePage: true,
validation: {},
editorConfig: {
language: "en",
extraPlugins: ["bidi", "justify"],
},
portals: null,
allNewsFile: null,
tempAllNewsFile: [],
filterParent: null,
};
},
mixins: [axiosUploadProcess],
computed: {
title() {
return this.$route.params.details === "new" ? "افزودن پرونده خبری جدید" : "مشاهده جزئیات پرونده خبری"
},
catId: {
get() {
if (this.$route.params.details === 'new') {
return this.newsFile.catId
} else {
return this.newsFile.catId._id
}
},
set(value) {
if (this.$route.params.details === 'new') {
this.newsFile.catId = value
} else {
this.newsFile.catId._id = value
}
}
}
},
watch: {
catId(newVal, oldVal) {
this.tempAllNewsFile = this.allNewsFile.filter(item => item.catId === newVal);
}
},
methods: {
imagePreview(e) {
this.newsFile.cover = URL.createObjectURL(e.target.files[0]);
},
changePortalVal(value) {
this.catId = null;
if (this.$auth.user.specialPermissions.length) {
this.filterParent = this.parents.filter(
(item) => item.modelType === value
).filter((item) => {
return this.$auth.user.specialPermissions.includes(item._id)
});
} else {
this.filterParent = this.parents.filter(
(item) => item.modelType === value
);
}
},
availableCategory(id) {
return this.$auth.user.permissions.includes('superAdmin') || this.$auth.user.specialPermissions.includes(id)
},
post() {
this.validation = {};
const data = new FormData();
data.append("title", this.newsFile.title.trim());
data.append("catId", this.catId);
data.append("description", this.newsFile.description.trim());
data.append("showInHome", this.newsFile.showInHome);
data.append("modelType", this.newsFile.modelType);
data.append("index", this.newsFile.index);
if (this.$refs.cover.files[0]) data.append('cover', this.$refs.cover.files[0]);
this.$axios
.post(`/api/admin/newsFile`, data, this.axiosConfig)
.then((response) => {
this.$message({
type: "success",
message: "پرونده خبری با موفقیت ایجاد شد.",
});
this.$router.push({
name: "admin-newsFile",
});
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
if (err.response.status === 500) {
return this.$message({
type: "error",
message: "مشکلی در ارسال درخواست پیش آمده",
});
}
if (err.response.status === 422)
this.validation = err.response.data.validation;
else console.log(err.response.data);
});
},
update() {
this.validation = {};
const data = new FormData();
data.append("title", this.newsFile.title.trim());
data.append("description", this.newsFile.description.trim());
data.append("catId", this.catId);
data.append("showInHome", this.newsFile.showInHome);
data.append("modelType", this.newsFile.modelType);
data.append("index", this.newsFile.index);
if (this.$refs.cover.files[0]) data.append('cover', this.$refs.cover.files[0]);
this.$axios
.put(`/api/admin/newsFile/${this.newsFile._id}`, data, this.axiosConfig)
.then((response) => {
this.$message({
type: "success",
message: "اطلاعات بروزرسانی شد.",
});
this.$refs.cover.value = null
this.$nuxt.refresh();
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
if (err.response.status === 500) {
return this.$message({
type: "error",
message: "مشکلی در ارسال درخواست پیش آمده",
});
}
if (err.response.status === 422)
this.validation = err.response.data.validation;
else console.log(err.response.data);
});
},
},
head() {
return {
title: this.title,
}
},
layout: "admin",
async asyncData({$axios, $auth, params, query, error}) {
try {
// const allNewsFile = await $axios.get("/api/admin/newsFile", { progress: false });
// const portals = await $axios.get("/api/admin/portals", { progress: false });
const requests = [
$axios.get("/api/admin/category/getParent", {params: {type: "news"}}),
$axios.get("/api/admin/newsFile"),
$axios.get("/api/admin/portals")
]
const fetch = await Promise.all(requests);
let [parents, allNewsFile, portals] = fetch
const setModelType = $auth.user.portals.length !== 1 ? $auth.user.portals : $auth.user.portals[0]
const setFilterParent = $auth.user.portals.length !== 1 ? null : parents.data.filter((item) => item.modelType === $auth.user.portals[0])
if (params.details !== "new") {
const newsFile = await $axios.get(`/api/admin/newsFile/${params.details}`)
return {
portals: portals.data,
parents: parents.data,
filterParent: parents.data,
allNewsFile: allNewsFile.data,
newsFile: newsFile.data
}
} else {
return {
portals: portals.data,
parents: parents.data,
filterParent: setFilterParent,
allNewsFile: allNewsFile.data,
newsFile: {
title: '',
description: '',
cover: '',
catId: $auth.user.specialPermissions,
index: null,
showInHome: true,
showInMenu: false,
siteMap: true,
modelType: setModelType,
}
}
}
} catch (e) {
if (e?.response?.status === 401) {
error({
status: 401,
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (e?.response?.status === 403) {
error({
status: 403,
message: e?.response?.data?.message,
});
}
if (e?.response?.status === 500) {
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات پیش آمده",
});
} else
error({
status: 404,
message: "پرونده خبری مورد نظر پیدا نشد",
});
}
}
}
</script>
+327
View File
@@ -0,0 +1,327 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="success" :to="{ name: 'admin-newsFile-details', params: { details: 'new' } }"
class="mr-auto">افزودن</CButton>
</CustomSubHeader>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-filter"></i>
<span style="color:#000">فیلتر</span>
</slot>
</CCardHeader>
<CCardBody>
<CRow>
<CCol md="6">
<CRow style="flex-direction : column;">
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>عنوان</span>
</CCol>
<CCol col="md-9">
<el-input style="width : 100%" placeholder="" v-model="search.term"></el-input>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3" v-if="$auth.user.permissions.includes('superAdmin')">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>نمایش در صفحه اصلی</span>
</CCol>
<CCol col="md-9">
<el-select v-model="search.showInHome" clearable style="width : 100%">
<el-option :key="true" label="بله" :value="true">
</el-option>
<el-option :key="false" label="خیر" :value="false">
</el-option>
</el-select>
</CCol>
</CRow>
</CCol>
</CRow>
</CCol>
<CCol md="6">
<CRow style="flex-direction : column;">
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>قسمت</span>
</CCol>
<CCol col="md-9">
<el-select v-model="search.portals" clearable style="width : 100%">
<el-option v-for="item in portals" :key="item.value" :label="item.name" :value="item.value">
</el-option>
</el-select>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>دسته بندی</span>
</CCol>
<CCol col="md-9">
<el-select filterable clearable style="width : 100%" v-model="search.catId"
placeholder="انتخاب دسته بندی">
<el-option v-for="item in parents" :key="item._id" :label="item.title" :value="item._id">
<!-- <span>{{setTitle(item)}}</span> -->
</el-option>
</el-select>
</CCol>
</CRow>
</CCol>
</CRow>
</CCol>
</CRow>
<CRow>
<el-button :loading="loading" @click="handleSearch" size="small" style="width: auto;margin: 25px auto auto auto;" type="primary"
icon="el-icon-search">
جست و جو</el-button>
</CRow>
</CCardBody>
</CCard>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>{{ list_title }}</span>
</slot>
<slot> </slot>
</CCardHeader>
<CCardBody>
<el-table v-loading="loading" :data="newsFile.docs" :default-sort="{ prop: 'date', order: 'descending' }" style="width: 100%">
<el-table-column type="index" label="#"> </el-table-column>
<el-table-column label="عنوان">
<template slot-scope="scope">
<span class="title">
<el-popover placement="top-end" trigger="hover" :content="scope.row.title">
<i v-if="scope.row.title.length > 25" class="el-icon-info" slot="reference"></i>
</el-popover>
{{ scope.row.title }}
</span>
</template>
</el-table-column>
<el-table-column label="کاربر">
<template slot-scope="scope">
<span v-if="!$auth.user.permissions.includes('superAdmin')">{{
scope.row._creator.firstName + " " + scope.row._creator.lastName
}}</span>
<nuxt-link v-else :to="{
name: 'admin-users-profile',
params: { profile: scope.row._creator._id },
}"><span style="color: blue;">{{
scope.row._creator.firstName +
" " +
scope.row._creator.lastName
}}</span></nuxt-link>
</template>
</el-table-column>
<el-table-column prop="catId.title" label="دسته بندی" width="">
<!-- <template slot-scope="scope">-->
<!-- <span>{{ scope.row.catId.title }}</span>-->
<!-- </template>-->
</el-table-column>
<el-table-column label="نمایش در صفحه اصلی" width="">
<template slot-scope="scope">
<el-tag :type="scope.row.showInHome ? 'primary' : 'danger'">{{
scope.row.showInHome ? "بله" : "خیر"
}}</el-tag>
</template>
</el-table-column>
<el-table-column label="تاریخ ایجاد" width="">
<template slot-scope="scope">
<span>{{ jDate(scope.row.created_at) }}</span>
</template>
</el-table-column>
<el-table-column label="ویرایش" width="110" align="center">
<template slot-scope="scope">
<CButton color="danger" variant="outline" :key="scope.row._id + Math.random()"
@click="deleteNewsFile(scope.row._id)">
<i class="far fa-trash-alt"></i>
</CButton>
<CButton color="success" variant="outline" :key="scope.row._id" :to="{
name: 'admin-newsFile-details',
params: { details: scope.row._id },
}">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
<CCard class="col" v-if="newsFile.totalDocs>5">
<CRow alignHorizontal="center" style="padding : 10px">
<el-pagination :hide-on-single-page="true" layout="prev, pager, next" :page-size="newsFile.limit"
@current-change="handleCurrentChange" :current-page.sync="newsFile.page" :total="newsFile.totalDocs">
</el-pagination>
</CRow>
</CCard>
</div>
</template>
<script>
import moment from "moment-jalaali";
export default {
data() {
return {
title: "لیست پرونده های خبری",
list_title: "لیست",
newsFile: null,
search: {},
portals: [],
loading : false
};
},
computed: {
pageQuery() {
return this.$route.query.page;
}
},
watch: {
pageQuery(newPage, oldPage) {
this.$nuxt.refresh();
}
},
methods: {
jDate(date) {
return moment(date).format("jYYYY/jMM/jDD");
},
deleteNewsFile(id) {
this.$confirm("پرونده خبری حذف شود؟", "اخطار", {
confirmButtonText: "بله",
cancelButtonText: "لغو",
type: "warning",
})
.then(async () => {
this.$axios
.delete(`/api/admin/newsFile/${id}`)
.then((res) => {
this.$message({
type: "success",
message: "پرونده خبری با موفقیت حذف شد",
});
this.$nuxt.refresh();
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
if (err.response.status === 422) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
console.log(err.response.data);
});
})
.catch(() => {
this.$message({
type: "warning",
message: "عملیات لغو شد",
});
});
},
handleCurrentChange(page) {
this.handleSearch(page);
},
handleSearch(page) {
this.loading = true;
const data = {
term: this.search.term,
catId: this.search.catId,
showInHome: this.search.showInHome,
portals: this.search.portals
}
this.$axios.post(`/api/admin/newsFile/search?page=${page}`, data, this.axiosConfig)
.then((result) => {
this.newsFile = result.data;
this.loading = false;
})
.catch(err => {
this.loading = false;
if (err.response.status === 401) {
return this.$message({
type: 'error',
message: 'لطفا دوباره وارد سیستم شوید.'
})
}
if (err.response.status === 422) this.validation = err.response.data.validation
else console.log(err.response.data)
})
},
},
head() {
return {
title: this.title,
};
},
layout: "admin",
async asyncData({
$axios,
error
}) {
try {
// const newsFile = await $axios.post(`/api/admin/newsFile/search`, { progress: false });
// const portals = await $axios.get('/api/admin/portals');
const requests = [
$axios.post(`/api/admin/newsFile/search`, { progress: false }),
$axios.get('/api/admin/portals'),
$axios.get("/api/admin/category/getParent", {
params: {
type: "news",
},
})
];
const fetch = await Promise.all(requests);
let [newsFile, portals , parents] = fetch;
return {
newsFile: newsFile.data,
parents: parents.data,
portals: portals.data
};
} catch (e) {
if(e?.response?.status === 401){
error({
status: 401,
message: 'شما اجازه دسترسی به این صفحه را ندارید'
})
}else{
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات بوجود آمده است",
});
}
}
},
};
</script>
+287
View File
@@ -0,0 +1,287 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="primary" class="mr-auto" :to="{ name: 'admin-occasion' }">برگشت به صفحه قبل</CButton>
<CButton v-if="$route.params.details === 'new'" size="sm" color="success" class="mr-1" @click="post">افزودن
</CButton>
<CButton v-else size="sm" color="success" class="mr-1" @click="update">بروزرسانی</CButton>
</CustomSubHeader>
<CRow style="display : flex ; flex-direction: column">
<CRow>
<CCol lg="6">
<CCard>
<CCardBody>
<CCol sm="12">
<CTextarea :class="validation.title ? 'err' : null" label="عنوان" :description="
validation.title ? validation.title.msg : null
" v-model="occasion.title" />
</CCol>
<el-divider></el-divider>
<CCol sm="12">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>تاریخ شروع</span>
</CCol>
<CCol col="md-9">
<date-picker clearable :min="nowDate" format="YYYY-MM-DD" display-format="jMMMM jD"
v-model="occasion.startDate"></date-picker>
</CCol>
<p style="margin-top : 5px !important ; color: red;" class="form-err" v-if="validation.startDate">
{{ validation.startDate.msg }}
</p>
</CRow>
</CCol>
<CCol sm="12">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>تاریخ اتمام</span>
</CCol>
<CCol col="md-9">
<date-picker clearable :min="occasion.startDate || nowDate" format="YYYY-MM-DD" display-format="jMMMM jD"
v-model="occasion.endDate"></date-picker>
</CCol>
<p style="margin-top : 5px !important ; color: red;" class="form-err" v-if="validation.endDate">
{{ validation.endDate.msg }}
</p>
</CRow>
</CCol>
</CCardBody>
</CCard>
</CCol>
<CCol lg="6">
<CCard>
<CCardBody>
<CCol sm="12">
<el-checkbox v-model="occasion.publish"
label="نمایش مناسبت" />
</CCol>
<el-divider></el-divider>
<CCol sm="12">
<h6 class="mt-2">ترتیب نمایش</h6>
<el-select style="width:100%" class="mt-2" v-model="occasion.index" placeholder="">
<el-option
v-for="item in allOccasion.length + 10"
v-if="!allOccasion.find((item2) => item2.index === item)"
:key="item"
:label="item"
:value="item">
</el-option>
</el-select>
<p style="margin-top : 5px !important ; color: red;" class="form-err" v-if="validation.index">
{{ validation.index.msg }}
</p>
</CCol>
</CCardBody>
</CCard>
</CCol>
</CRow>
<CRow>
<CCol>
<CCard>
<CCardBody>
<CCol sm="12">
<h5>بنر</h5>
<el-divider />
<CCol>
<img :src="occasion.mainCover" style="width: 100%;" alt="" />
</CCol>
<input type="file" ref="cover" @change="imagePreview" />
<p style="margin-top : 5px !important ; color: red;" class="form-err" v-if="validation.cover">
{{ validation.cover.msg }}
</p>
<p class="mt-3 text-muted">
عکس 1920*180 باشد. در غیر این صورت اتوماتیک بریده می شود.
</p>
</CCol>
</CCardBody>
</CCard>
</CCol>
</CRow>
</CRow>
</div>
</template>
<script>
import axiosUploadProcess from "@/mixins/axiosUploadProcess";
import moment from "moment-jalaali";
export default {
data() {
return {
occasion: null,
validation: {},
editorConfig: {
language: "en",
extraPlugins: ["bidi", "justify"],
},
loading : false,
allOccasion : null
};
},
mixins: [axiosUploadProcess],
computed: {
title() {
return this.$route.params.details === "new" ?
"افزودن مناسبت جدید" :
"مشاهده جزئیات مناسبت";
},
nowDate(){
return moment().format('YYYY-MM-DD')
},
},
methods: {
imagePreview(e) {
this.occasion.cover = URL.createObjectURL(e.target.files[0]);
},
post() {
this.validation = {};
const data = new FormData();
data.append("title", this.occasion.title.trim());
data.append("startDate", this.occasion.startDate);
data.append("endDate", this.occasion.endDate);
data.append("index", this.occasion.index);
data.append("publish", this.occasion.publish);
data.append("status", this.occasion.status);
if (this.$refs.cover.files[0])
data.append("cover", this.$refs.cover.files[0]);
this.$axios
.post(`/api/admin/occasion`, data, this.axiosConfig)
.then((response) => {
this.$message({
type: "success",
message: "مناسبت با موفقیت ایجاد شد.",
});
this.$router.push({
name: "admin-occasion",
});
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
if (err.response.status === 500) {
return this.$message({
type: "error",
message: "مشکلی در ارسال درخواست پیش آمده",
});
}
if (err.response.status === 422)
this.validation = err.response.data.validation;
else console.log(err.response.data);
});
},
update() {
this.validation = {};
const data = new FormData();
data.append("title", this.occasion.title.trim());
data.append("startDate", this.occasion.startDate);
data.append("endDate", this.occasion.endDate);
data.append("index", this.occasion.index);
data.append("publish", this.occasion.publish);
data.append("status", this.occasion.status);
if (this.$refs.cover.files[0])
data.append("cover", this.$refs.cover.files[0]);
this.$axios
.put(`/api/admin/occasion/${this.occasion._id}`, data, this.axiosConfig)
.then((response) => {
this.$message({
type: "success",
message: "اطلاعات بروزرسانی شد.",
});
this.$nuxt.refresh();
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
if (err.response.status === 500) {
return this.$message({
type: "error",
message: "مشکلی در ارسال درخواست پیش آمده",
});
}
if (err.response.status === 422)
this.validation = err.response.data.validation;
else console.log(err.response.data);
});
},
},
head() {
return {
title: this.title,
};
},
layout: "admin",
async asyncData({$axios, $auth, params, query, error}) {
try {
const allOccasion = await $axios.get(`/api/admin/occasion/allOccasion`);
if (params.details !== "new") {
const occasion = await $axios.get(`/api/admin/occasion/${params.details}`);
return {
occasion: occasion.data,
allOccasion : allOccasion.data
};
} else {
return {
allOccasion : allOccasion.data,
occasion: {
title: '',
mainCover: '',
startDate: '',
endDate: '',
index: null,
publish: true
},
};
}
} catch (e) {
if (e?.response?.status === 401) {
error({
status: 401,
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (e?.response?.status === 403) {
error({
status: 403,
message: e?.response?.data?.message,
});
}
if (e?.response?.status === 500) {
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات پیش آمده",
});
} else
error({
status: 404,
message: "مناسبت مورد نظر پیدا نشد",
});
}
},
};
</script>
+320
View File
@@ -0,0 +1,320 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="success" :to="{ name: 'admin-occasion-details', params: { details: 'new' } }"
class="mr-auto">افزودن
</CButton>
</CustomSubHeader>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-filter"></i>
<span style="color:#000">فیلتر</span>
</slot>
</CCardHeader>
<CCardBody>
<CRow>
<CCol md="6">
<CRow style="flex-direction : column;">
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>عنوان</span>
</CCol>
<CCol col="md-9">
<el-input style="width : 100%" placeholder="" v-model="search.term"></el-input>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>تاریخ</span>
</CCol>
<CCol col="md-9">
<date-picker range clearable format="YYYY-MM-DD" display-format="jMMMM jD"
v-model="search.date"></date-picker>
</CCol>
</CRow>
</CCol>
</CRow>
</CCol>
<CCol md="6">
<CRow style="flex-direction : column;">
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>وضعیت نمایش</span>
</CCol>
<CCol col="md-9">
<el-select v-model="search.publish" clearable style="width : 100%" placeholder="">
<el-option :key="true" label="نمایش داده شود" :value="true">
</el-option>
<el-option :key="false" label="نمایش داده نشود" :value="false">
</el-option>
</el-select>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>وضعیت مناسبت</span>
</CCol>
<CCol col="md-9">
<el-select filterable clearable style="width : 100%" v-model="search.status"
placeholder="">
<el-option :key="true" label="کامل" :value="true">
</el-option>
<el-option :key="false" label="ناقص" :value="false">
</el-option>
</el-select>
</CCol>
</CRow>
</CCol>
</CRow>
</CCol>
</CRow>
<CRow>
<el-button :loading="loading" @click="handleSearch" size="small"
style="width: auto;margin: 25px auto auto auto;" type="primary"
icon="el-icon-search">
جست و جو
</el-button>
</CRow>
</CCardBody>
</CCard>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>{{ list_title }}</span>
</slot>
<slot></slot>
</CCardHeader>
<CCardBody>
<el-table v-loading="loading" :data="occasion.docs" :default-sort="{ prop: 'date', order: 'descending' }"
style="width: 100%">
<el-table-column type="index" label="#"></el-table-column>
<el-table-column label="عنوان">
<template slot-scope="scope">
<span class="title">
<el-popover placement="top-end" trigger="hover" :content="scope.row.title">
<i v-if="scope.row.title.length > 25" class="el-icon-info" slot="reference"></i>
</el-popover>
{{ scope.row.title }}
</span>
</template>
</el-table-column>
<el-table-column label="کاربر">
<template slot-scope="scope">
<span v-if="!$auth.user.permissions.includes('superAdmin')">{{
scope.row._creator.firstName + " " + scope.row._creator.lastName
}}</span>
<nuxt-link v-else :to="{
name: 'admin-users-profile',
params: { profile: scope.row._creator._id },
}"><span style="color: blue;">{{
scope.row._creator.firstName +
" " +
scope.row._creator.lastName
}}</span></nuxt-link>
</template>
</el-table-column>
<el-table-column label="وضعیت نمایش" width="">
<template slot-scope="scope">
<el-tag :type="scope.row.publish ? 'primary' : 'danger'">{{
scope.row.publish ? "نمایش داده شود" : "نمایش داده نشود"
}}
</el-tag>
</template>
</el-table-column>
<el-table-column label="وضعیت مناسبت" width="">
<template slot-scope="scope">
<el-tag :type="scope.row.status ? 'primary' : 'danger'">{{
scope.row.status ? "کامل" : "ناقص"
}}
</el-tag>
</template>
</el-table-column>
<el-table-column label="تاریخ شروع" width="">
<template slot-scope="scope">
<span>{{ jDate(scope.row.startDate) }}</span>
</template>
</el-table-column>
<el-table-column label="تاریخ پایان" width="">
<template slot-scope="scope">
<span>{{ jDate(scope.row.endDate) }}</span>
</template>
</el-table-column>
<el-table-column label="ویرایش" width="110" align="center">
<template slot-scope="scope">
<CButton color="danger" variant="outline" :key="scope.row._id + Math.random()"
@click="deleteOccasion(scope.row._id)">
<i class="far fa-trash-alt"></i>
</CButton>
<CButton color="success" variant="outline" :key="scope.row._id" :to="{
name: 'admin-occasion-details',
params: { details: scope.row._id },
}">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
<CCard class="col" v-if="occasion.totalDocs>5">
<CRow alignHorizontal="center" style="padding : 10px">
<el-pagination :hide-on-single-page="true" layout="prev, pager, next" :page-size="occasion.limit"
@current-change="handleCurrentChange" :current-page.sync="occasion.page"
:total="occasion.totalDocs">
</el-pagination>
</CRow>
</CCard>
</div>
</template>
<script>
import moment from "moment-jalaali";
export default {
data() {
return {
title: "لیست مناسبت ها",
list_title: "لیست",
occasion: null,
search: {},
loading: false
};
},
computed: {
pageQuery() {
return this.$route.query.page;
}
},
watch: {
pageQuery(newPage, oldPage) {
this.$nuxt.refresh();
}
},
methods: {
jDate(date) {
return moment(date).format("jYYYY/jMM/jDD");
},
deleteOccasion(id) {
this.$confirm("پرونده خبری حذف شود؟", "اخطار", {
confirmButtonText: "بله",
cancelButtonText: "لغو",
type: "warning",
})
.then(async () => {
this.$axios
.delete(`/api/admin/occasion/${id}`)
.then((res) => {
this.$message({
type: "success",
message: "پرونده خبری با موفقیت حذف شد",
});
this.$nuxt.refresh();
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
if (err.response.status === 422) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
console.log(err.response.data);
});
})
.catch(() => {
this.$message({
type: "warning",
message: "عملیات لغو شد",
});
});
},
handleCurrentChange(page) {
this.handleSearch(page);
},
handleSearch(page) {
this.loading = true;
const data = {
term: this.search.term,
status: this.search.status,
publish: this.search.publish,
date: this.search.date
}
this.$axios.post(`/api/admin/occasion/search?page=${page || 1}`, data, this.axiosConfig)
.then((result) => {
this.occasion = result.data;
this.loading = false;
})
.catch(err => {
this.loading = false;
if (err.response.status === 401) {
return this.$message({
type: 'error',
message: 'لطفا دوباره وارد سیستم شوید.'
})
}
if (err.response.status === 422) this.validation = err.response.data.validation
else console.log(err.response.data)
})
},
},
head() {
return {
title: this.title,
};
},
layout: "admin",
async asyncData({$axios, error, query}) {
try {
const occasion = await $axios.get(`/api/admin/occasion?page=${query.page || 1}`);
return {
occasion: occasion.data
};
} catch (e) {
if (e?.response?.status === 401) {
error({
status: 401,
message: 'شما اجازه دسترسی به این صفحه را ندارید'
})
} else {
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات بوجود آمده است",
});
}
}
},
};
</script>
+694
View File
@@ -0,0 +1,694 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="primary" class="mr-auto" :to="{ name: 'admin-pages' }">برگشت به صفحه قبل</CButton>
<CButton v-if="$route.params.details === 'new'" size="sm" color="success" class="mr-1" @click="post">افزودن
</CButton>
<CButton v-else size="sm" color="success" class="mr-1" @click="update">بروزرسانی</CButton>
</CustomSubHeader>
<CRow>
<CCol sm="12">
<CCard>
<CCardBody>
<CForm>
<CRow>
<CCol lg="6">
<h6>قسمت انتخابی <i v-c-tooltip="'شما باید تعیین کنید که این صفحه برای کدام قسمت پرتال می باشد'"
class="fas fa-question-circle"></i></h6>
<el-select
:disabled="$route.params.details !== 'new' ? true : $auth.user.portals.length===1"
v-model="page.modelType"
placeholder="انتخاب کنید"
style="width: 100%;"
>
<el-option
v-for="item in portals"
:key="item.value"
:label="item.name"
:value="item.value"
>
</el-option>
</el-select>
<p style="margin-top : 5px !important ; color : red" class="form-err" v-if="validation.modelType">
{{ validation.modelType.msg }}</p>
<el-divider/>
<template v-if="page.modelType">
<CRow>
<CCol sm="12">
<h6>{{ this.$route.params.details !== 'new' ? 'دسته بندی' : 'انتخاب دسته بندی' }}</h6>
<el-select :disabled="$route.params.details !== 'new'" filterable clearable style="width : 100%"
v-model="page.parent" placeholder="انتخاب دسته بندی">
<el-option v-for="item in filterParent" :key="item._id" :label="item.title" :value="item._id">
<!-- <span>{{setTitle(item)}}</span> -->
</el-option>
</el-select>
</CCol>
</CRow>
<el-divider/>
</template>
<CRow>
<CCol sm="12">
<CInput
:class="validation.title ? 'err' : null"
label="عنوان"
:description="validation.title ? validation.title.msg : null"
v-model="page.title"
/>
</CCol>
</CRow>
</CCol>
<CCol lg="6">
<!-- <CRow>-->
<!-- <CCol sm="12" class="mt-1">-->
<!-- <el-checkbox-->
<!-- v-model="showInFooter"-->
<!-- label="نمایش در پایین سایت"-->
<!-- @change="changeSetFooter"-->
<!-- />-->
<!-- <i v-c-tooltip="'با این گزینه می توانید تعیین کنید صفحه در کدام ستون پایین سایت قرار بگیرد'" class="fas fa-question-circle"></i>-->
<!-- <template v-if="showInFooter">-->
<!-- <el-radio-group style="display : inline-flex; margin-right:-30px" class="mt-3" v-model="page.showInFooter">-->
<!-- <el-radio :label="1">نمایش در ستون شماره 1</el-radio>-->
<!-- <el-radio :label="2">نمایش در ستون شماره 2</el-radio>-->
<!-- <el-radio :label="3">نمایش در ستون شماره 3</el-radio>-->
<!-- </el-radio-group>-->
<!-- </template>-->
<!-- </CCol>-->
<!-- </CRow>-->
<!-- <el-divider></el-divider>-->
<CRow>
<CCol sm="12" class="mt-1">
<el-checkbox v-model="page.child" label="این صفحه می تواند زیرمجموعه داشته باشد"/>
<i v-c-tooltip="'منظور از زیرمجموعه یعنی قرار گرفتن صفحات دیگر زیر این صفحه'"
class="fas fa-question-circle"></i>
</CCol>
<CCol v-if="typePage" sm="12" class="mt-1">
<el-checkbox v-model="page.news" label="این صفحه دارای اخبار باشد" @change="changeNews"/>
</CCol>
<el-divider></el-divider>
<p>تنظیمات درون صفحه:</p>
<div>
<el-checkbox
@change="clearDefaultType"
v-model="page.hasNewsTab"
label="در این صفحه دکمه بخش (اخبار) نمایش داده شود"
/>
<el-checkbox
@change="clearDefaultType"
v-model="page.hasNewsFileTab"
label="در این صفحه دکمه بخش (پرونده خبری) نمایش داده شود"
/>
<el-checkbox
@change="clearDefaultType"
v-model="page.hasContentTab"
label="در این صفحه دکمه بخش (درباره...) نمایش داده شود"
/>
<el-checkbox
@change="clearDefaultType"
v-model="page.hasMediaTab"
label="در این صفحه دکمه بخش (چندرسانه ای) نمایش داده شود"
/>
<el-checkbox
@change="clearDefaultType"
v-model="page.hasSubMenusTab"
label="در این صفحه دکمه بخش (صفحات مرتبط) نمایش داده شود"
/>
<el-checkbox
@change="clearDefaultType"
v-model="page.hasTermsTab"
label="در این صفحه دکمه بخش (قوانین و دستورالعمل ها) نمایش داده شود"
/>
<el-checkbox
@change="clearDefaultType"
v-model="page.hasNotificationsTab"
label="در این صفحه دکمه بخش (اطلاعیه ها) نمایش داده شود"
/>
<el-checkbox
@change="clearDefaultType"
v-model="page.hasSpecNewsTab"
label="در این صفحه دکمه بخش (مطالب ویژه) نمایش داده شود"
/>
<el-checkbox
@change="clearDefaultType"
v-model="page.hasNazarTab" style="margin-right: 30px;"
label="در این صفحه دکمه بخش (نظر سنجی) نمایش داده شود"
/>
</div>
<div class="mt-3">
<p>بخش پیش فرض هنگام ورود به این صفحه:</p>
<el-select v-model="page.defaultPageType">
<el-option v-if="page.hasNewsTab" label="اخبار" value="news"/>
<el-option v-if="page.hasNewsFileTab" label="پرونده خبری" value="newsFile"/>
<el-option v-if="page.hasContentTab" label="درباره..." value="content"/>
<el-option v-if="page.hasMediaTab" label="چندرسانه ای - تصاویر" value="gallery-image"/>
<el-option v-if="page.hasMediaTab" label="چندرسانه ای - فیلم ها" value="gallery-video"/>
<el-option v-if="page.hasMediaTab" label="چندرسانه ای - گرافیک ها" value="gallery-graphic"/>
<el-option v-if="page.hasSubMenusTab" label="صفحات مرتبط" value="subMenu"/>
<el-option v-if="page.hasTermsTab" label="قوانین و دستورالعمل ها" value="terms"/>
<el-option v-if="page.hasNotificationsTab" label="اطلاعیه ها" value="event"/>
<el-option v-if="page.hasSpecNewsTab" label="مطالب ویژه" value="special"/>
<el-option v-if="page.hasNazarTab" label="نظرسنجی" value="survey"/>
</el-select>
</div>
<!-- <template v-if="page.news">-->
<!-- <CCol sm="12" class="mt-1">-->
<!-- <el-checkbox-->
<!-- v-model="showInHome"-->
<!-- label="قرار گرفتن در صفحه اصلی پرتال"-->
<!-- @change="changeShowInHome"-->
<!-- />-->
<!-- <CRow>-->
<!-- <CCol sm="12">-->
<!-- <template v-if="showInHome">-->
<!-- <el-radio-group style="display : inline-flex; margin-right:-30px" class="mt-3" v-model="setShowHome">-->
<!-- <el-radio :label="1">نمایش در بخش اول</el-radio>-->
<!-- <el-radio :label="2">نمایش در بخش دوم</el-radio>-->
<!-- <el-radio :label="3">نمایش در بخش سوم</el-radio>-->
<!-- </el-radio-group>-->
<!-- </template>-->
<!-- </CCol>-->
<!-- </CRow>-->
<!-- </CCol>-->
<!-- </template>-->
</CRow>
<el-divider></el-divider>
<CRow>
<CCol sm="12" class="mt-1">
<template>
<h6 class="mt-2">ترتیب نمایش</h6>
<el-select style="width:100%" class="mt-2" v-model="page.navIndex" placeholder="">
<el-option
v-for="item in allPage.length + 10"
v-if="!allPage.find((item2) => item2.navIndex === item)"
:key="item"
:label="item"
:value="item">
</el-option>
</el-select>
<p class="text-danger" v-if="validation.navIndex">{{ validation.navIndex.msg }}</p>
</template>
</CCol>
</CRow>
</CCol>
<CCol lg="6">
<h4>مشخصات مدیر صفحه:</h4>
<el-divider></el-divider>
<img :src="page.managerCover" alt="" style="width: 100%;">
<input type="file" ref="managerCover" @change="imagePreview">
<el-divider></el-divider>
<el-checkbox
v-model="page.hasManagerInfo"
label="در این صفحه اطلاعات مدیر در سایدبار نمایش داده شود"
/>
<CInput
:class="validation.managerName ? 'err' : null"
label="نام و نام خانوادگی مدیر"
:description="validation.managerName ? validation.managerName.msg : null"
v-model="page.managerName"
/>
<CTextarea
:class="validation.managerDescription ? 'err' : null"
label="توضیحات کوتاه درباره مدیر"
:description="validation.managerDescription ? validation.managerDescription.msg : null"
rows="5"
v-model="page.managerDescription"
/>
</CCol>
</CRow>
<CRow>
<CCol>
<el-divider/>
<!-- <h6>این صفحه:</h6>-->
<!-- <el-radio-group class="mt-3" v-model="typePage">-->
<!-- <el-radio :label="true">دارای محتوا می باشد</el-radio>-->
<!-- <br>-->
<!-- <el-radio :label="false" style="margin-right: 30px;">-->
<!-- <span>به صورت یک لینک خارجی عمل نماید</span>-->
<!-- <i v-c-tooltip="'اگر شما این گزینه را انتخاب کنید صفحه شما به صورت یک لینک عمل می کند یعنی زمانی که کلیک شد روی صفحه به لینک مورد نظر انتقال پیدا می کند'"-->
<!-- class="fas fa-question-circle"></i>-->
<!-- </el-radio>-->
<!-- </el-radio-group>-->
<CRow>
<CCol sm="12" class="mb-3">
<!-- <CInput-->
<!-- v-if="!typePage"-->
<!-- :class="validation.url ? 'err' : null"-->
<!-- label="لینک"-->
<!-- :description="validation.url ? validation.url.msg : null"-->
<!-- v-model="page.url"-->
<!-- />-->
<template v-if="typePage">
<client-only>
<p>درباره ی</p>
<ckeditor v-model="page.pageContent" :config="editorConfig"></ckeditor>
<p class="text-danger" v-if="validation.pageContent">{{ validation.pageContent.msg }}</p>
</client-only>
</template>
</CCol>
</CRow>
</CCol>
</CRow>
</CForm>
</CCardBody>
</CCard>
</CCol>
<CCol sm="12" v-if="$route.params.details !== 'new'">
<CCard>
<CCardBody>
<CRow>
<CCol sm="6">
<h2>لیست فایل های قوانین و مقررات</h2>
<el-divider></el-divider>
<el-table :data="page.terms">
<el-table-column
type="index"
label="#"
>
</el-table-column>
<el-table-column
label="فایل"
width=""
>
<template slot-scope="scope">
<a :href="scope.row.file" target="_blank">{{ scope.row.title }}</a>
</template>
</el-table-column>
<el-table-column
label="ویرایش"
width="75"
align="center"
>
<template slot-scope="scope">
<CButton color="danger" variant="outline" @click="deleteFile(scope.row._id)">
<i class="far fa-trash-alt"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCol>
<CCol sm="6">
<h2>افزودن فایل برای قوانین و مقررات</h2>
<el-divider></el-divider>
<input type="file" ref="termsFile"/>
<p class="text-danger" v-if="validation.file">{{ validation.file.msg }}</p>
<br>
<br>
<label>
<input type="text" ref="termsTitle" placeholder="عنوان فایل را بنویسید" style="width: 300px;"/>
</label>
<p class="text-danger" v-if="validation.termsTitle">{{ validation.termsTitle.msg }}</p>
<br>
<br>
<el-button size="small" type="success" @click="addFile">افزودن</el-button>
</CCol>
</CRow>
</CCardBody>
</CCard>
</CCol>
</CRow>
</div>
</template>
<script>
import axiosUploadProcess from "@/mixins/axiosUploadProcess"
export default {
data() {
return {
page: null,
typePage: true,
validation: {},
showInHome: false,
editorConfig: {
language: 'en',
extraPlugins: ['bidi', 'justify']
},
filterParent: [],
portals: null,
showInFooter: false,
parents: null,
allPage: null,
allParents: null
}
},
mixins: [axiosUploadProcess],
computed: {
title() {
return this.$route.params.details === 'new' ? 'افزودن صفحه جدید' : 'مشاهده جزئیات صفحه'
},
parent() {
return this.page.parent
},
modelType() {
return this.page.modelType
}
},
watch: {
parent(newVal, oldVal) {
if (newVal) this.allPage = this.allParents.filter(item => item.parent === newVal);
else this.allPage = this.allParents.filter(item => item.modelType === this.page.modelType && item.parent === null);
},
modelType(newVal, oldVal) {
this.page.parent = null;
this.page.navIndex = null;
this.filterParent = this.parents.filter(item => item.modelType === newVal);
this.allPage = this.allParents.filter(item => item.modelType === newVal && item.parent === null);
}
},
methods: {
changeSetFooter(value) {
if (!value) {
this.page.showInFooter = 0;
}
},
changeNews() {
this.showInHome = false;
// this.setShowHome = null;
},
imagePreview(e) {
this.page.managerCover = URL.createObjectURL(e.target.files[0])
},
post() {
this.validation = {}
const data = new FormData()
data.append("title", this.page.title.trim())
if (this.page.parent) data.append("parent", this.page.parent.trim())
data.append("navIndex", this.page.navIndex)
data.append("priority", this.page.priority)
data.append("siteMap", this.page.siteMap)
data.append("special", this.page.special)
data.append("showInFooter", this.page.showInFooter)
if (this.page.url) data.append("url", this.page.url)
data.append("pageContent", this.page.pageContent)
data.append("news", this.page.news)
data.append("child", this.page.child)
data.append("modelType", this.page.modelType)
data.append("hasNewsTab", this.page.hasNewsTab)
data.append("hasContentTab", this.page.hasContentTab)
data.append("hasMediaTab", this.page.hasMediaTab)
data.append("hasSubMenusTab", this.page.hasSubMenusTab)
data.append("hasTermsTab", this.page.hasTermsTab)
data.append("hasNotificationsTab", this.page.hasNotificationsTab)
data.append("hasSpecNewsTab", this.page.hasSpecNewsTab)
data.append("hasNazarTab", this.page.hasNazarTab)
data.append("hasNewsFileTab", this.page.hasNewsFileTab)
data.append("defaultPageType", this.page.defaultPageType)
data.append("hasManagerInfo", this.page.hasManagerInfo)
data.append("managerName", this.page.managerName)
data.append("managerDescription", this.page.managerDescription)
if (this.$refs.managerCover.files[0]) data.append("managerCover", this.$refs.managerCover.files[0])
this.$axios.post(`/api/admin/category`, data, this.axiosConfig)
.then(response => {
this.$message({
type: 'success',
message: 'صفحه با موفقیت ایجاد شد.'
})
this.$router.push({
name: 'admin-pages'
})
})
.catch(err => {
if (err.response.status === 401) {
return this.$message({
type: 'error',
message: 'لطفا دوباره وارد سیستم شوید.'
})
}
if (err.response.status === 403) {
return this.$message({
type: 'error',
message: err.response.data.message
})
}
if (err.response.status === 500) {
return this.$message({
type: 'error',
message: 'مشکلی در ارسال درخواست پیش آمده'
})
}
if (err.response.status === 422) {
this.$message({
type: 'warning',
message: 'پارامترها را بررسی کنید'
})
this.validation = err.response.data.validation
} else console.log(err.response.data)
})
},
update() {
this.validation = {};
const data = new FormData();
data.append("title", this.page.title.trim())
if (this.page.parent) {
data.append("parent", this.page.parent);
}
data.append("navIndex", this.page.navIndex)
data.append("priority", this.page.priority)
data.append("siteMap", this.page.siteMap)
data.append("special", this.page.special)
data.append("showInFooter", this.page.showInFooter)
if (this.page.url) data.append("url", this.page.url)
data.append("pageContent", this.page.pageContent)
data.append("news", this.page.news)
data.append("child", this.page.child)
data.append("modelType", this.page.modelType)
data.append("hasNewsTab", this.page.hasNewsTab)
data.append("hasContentTab", this.page.hasContentTab)
data.append("hasMediaTab", this.page.hasMediaTab)
data.append("hasSubMenusTab", this.page.hasSubMenusTab)
data.append("hasTermsTab", this.page.hasTermsTab)
data.append("hasNotificationsTab", this.page.hasNotificationsTab)
data.append("hasSpecNewsTab", this.page.hasSpecNewsTab)
data.append("hasNazarTab", this.page.hasNazarTab)
data.append("hasNewsFileTab", this.page.hasNewsFileTab)
data.append("defaultPageType", this.page.defaultPageType)
data.append("hasManagerInfo", this.page.hasManagerInfo)
data.append("managerName", this.page.managerName)
data.append("managerDescription", this.page.managerDescription)
if (this.$refs.managerCover.files[0]) data.append("managerCover", this.$refs.managerCover.files[0])
this.$axios.put(`/api/admin/category/${this.page._id}`, data, this.axiosConfig)
.then(response => {
this.$message({
type: 'success',
message: 'اطلاعات بروزرسانی شد.'
})
this.$refs.managerCover.value = null
this.$nuxt.refresh()
})
.catch(err => {
if (err.response.status === 401) {
return this.$message({
type: 'error',
message: 'لطفا دوباره وارد سیستم شوید.'
})
}
if (err.response.status === 403) {
return this.$message({
type: 'error',
message: err.response.data.message
})
}
if (err.response.status === 500) {
return this.$message({
type: 'error',
message: 'مشکلی در ارسال درخواست پیش آمده'
})
}
if (err.response.status === 422) {
this.$message({
type: 'warning',
message: 'پارامترها را بررسی کنید'
})
this.validation = err.response.data.validation
} else console.log(err.response.data);
})
},
addFile() {
this.validation = {}
const data = new FormData()
data.append('file', this.$refs.termsFile.files[0])
data.append('termsTitle', this.$refs.termsTitle.value)
this.$axios.post(`/api/admin/category/termsFile/${this.page._id}`, data, this.axiosConfig)
.then(res => {
this.$message({
type: 'success',
message: 'فایل با موفقیت اضافه شد'
})
this.$refs.termsFile.value = null
this.$refs.termsTitle.value = null
this.$nuxt.refresh()
})
.catch(err => {
if (err.response.status === 401) {
return this.$message({
type: 'error',
message: 'لطفا دوباره وارد سیستم شوید.'
})
}
if (err.response.status === 403) {
return this.$message({
type: 'error',
message: err.response.data.message
})
}
if (err.response.status === 500) {
return this.$message({
type: 'error',
message: 'مشکلی در ارسال درخواست پیش آمده'
})
}
if (err.response.status === 422) {
this.$message({
type: 'warning',
message: 'پارامترها را بررسی کنید'
})
this.validation = err.response.data.validation
} else console.log(err.response.data);
})
},
deleteFile(id) {
this.$confirm('فایل حذف شود؟', 'هشدار', {
confirmButtonText: 'بله',
cancelButtonText: 'لغو',
type: 'warning'
})
.then(async () => {
this.$axios.delete(`/api/admin/category/termsFile/${id}`)
.then(res => {
this.$message({
type: 'success',
message: 'فایل با موفقیت حذف شد'
})
this.page.terms = this.page.terms.filter(item => item._id !== id)
})
.catch(err => {
if (err.response.status === 401) {
return this.$message({
type: 'error',
message: 'لطفا دوباره وارد سیستم شوید.'
})
}
if (err.response.status === 403) {
return this.$message({
type: 'error',
message: err.response.data.message
})
}
if (err.response.status === 422) {
return this.$message({
type: 'error',
message: err.response.data.message
})
}
console.log(err.response.data)
})
})
.catch(() => {
this.$message({
type: 'warning',
message: 'عملیات لغو شد'
})
})
},
clearDefaultType() {
this.page.defaultPageType = 'news'
}
},
head() {
return {
title: this.title
}
},
layout: 'admin',
async asyncData({$axios, $auth, params, query, error}) {
try {
const requests = [
$axios.get('/api/admin/category/permissions', {progress: false}),
$axios.get('/api/admin/category/getParent', {progress: false}),
$axios.get('/api/admin/portals')
];
const fetch = await Promise.all(requests);
let [allParents, parents, portals] = fetch;
if (params.details !== 'new') {
const pages = await $axios.get(`/api/admin/category/${params.details}`);
return {
portals: portals.data,
parents: parents.data,
page: pages.data,
allPage: allParents.data.filter(item => item.parent === pages.data.parent),
allParents: allParents.data,
showInFooter: pages.data.showInFooter !== 0,
filterParent: allParents.data
}
} else {
return {
portals: portals.data,
parents: parents.data,
allPage: query.type ? allParents.data.filter(item => item.parent === query.parent) : allParents.data,
allParents: allParents.data,
filterParent: parents.data,
page: {
title: '',
parent: query ? query.parent : '',
navIndex: null,
priority: 0,
level: 1,
siteMap: true,
special: false,
showInFooter: 0,
url: '',
pageContent: null,
news: true,
child: true,
hasNewsTab: true,
hasContentTab: true,
hasMediaTab: true,
hasSubMenusTab: true,
hasTermsTab: true,
hasNotificationsTab: true,
hasSpecNewsTab: true,
hasNazarTab: true,
hasNewsFileTab: true,
defaultPageType: 'news',
modelType: query.type ? query.type : $auth.user.portals.length !== 1 ? '' : $auth.user.portals[0],
hasManagerInfo: false,
managerName: '',
managerDescription: '',
managerCover: ''
}
}
}
} catch (e) {
if (e?.response?.status === 401) error({status: 401, message: "لطفا دوباره وارد سیستم شوید."})
if (e?.response?.status === 403) error({status: 403, message: e?.response?.data?.message})
if (e?.response?.status === 500) error({status: 500, message: "مشکلی در گرفتن اطلاعات پیش آمده"})
else error({status: 404, message: "صفحه مورد نظر پیدا نشد"})
}
}
}
</script>
+202
View File
@@ -0,0 +1,202 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton v-if="!$auth.user.specialPermissions.length" size="sm" color="success" :to="{name: 'admin-pages-details',params:{details: 'new'}}" class="mr-auto">
افزودن
</CButton>
</CustomSubHeader>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-filter"></i>
<span style="color:#000">فیلتر</span>
</slot>
</CCardHeader>
<CCardBody>
<CRow>
<CCol class="col">
<CRow>
<el-input
v-model="search"
size="medium"
placeholder="جستجو"/>
</CRow>
</CCol>
</CRow>
</CCardBody>
</CCard>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>{{ list_title }}</span>
</slot>
<slot>
</slot>
</CCardHeader>
<CCardBody>
<el-tree
:data="filteredPages"
:props="defaultProps"
class="filter-tree"
:filter-node-method="filterNode"
ref="tree"
@node-click="handleNodeClick"
>
<span class="custom-tree-node" slot-scope="{ node }">
<span style="flex: content;">{{ node.label }}</span>
<el-tag class="flagType" style="width: 80px;text-align: center;">{{
node.data.modelType === 'ostandari' ? 'استانداری' : 'ستاد انتخابات'
}}</el-tag>
<span style="margin-left: 10px;" class="btns">
<el-button
v-if="!$auth.user.specialPermissions.length"
type="text"
icon="el-icon-plus"
style="color : lightseagreen"
size="medium"
@click="() => append(node)">
</el-button>
<el-button
type="text"
icon="el-icon-edit-outline"
style="color : orange"
size="medium"
@click="() => goUpdate(node)">
</el-button>
<el-button
v-if="!$auth.user.specialPermissions.length"
type="text"
icon="el-icon-delete"
style="color : red"
size="medium"
@click="() => deletePage(node.data._id)">
</el-button>
</span>
</span>
</el-tree>
</CCardBody>
</CCard>
</div>
</template>
<script>
export default {
data() {
return {
title: 'لیست صفحات',
list_title: 'لیست',
pages: null,
search: '',
defaultProps: {
children: 'childs',
label: 'title'
}
}
},
computed: {
filteredPages() {
if (this.$auth.user.permissions.includes('superAdmin')) return this.pages
else return this.pages.map(item => {
return {
...item,
childs: []
}
})
}
},
watch: {
search(val) {
this.$refs.tree.filter(val);
}
},
methods: {
filterNode(value, data) {
if (!value) return true;
return data.title.indexOf(value) !== -1;
},
append(data) {
this.$router.push({
name: "admin-pages-details",
params: {details: 'new'},
query: {parent: data.data._id, type: data.data.modelType}
});
},
goUpdate(data) {
this.$router.push({name: "admin-pages-details", params: {details: data.data._id}});
},
handleNodeClick(data) {
// console.log(data);
},
deletePage(id) {
this.$confirm('صفحه حذف شود؟', 'هشدار', {
confirmButtonText: 'بله',
cancelButtonText: 'لغو',
type: 'warning'
}).then(async () => {
this.$axios.delete(`/api/admin/category/${id}`)
.then(res => {
this.$message({
type: 'success',
message: 'صفحه با موفقیت حذف شد'
})
this.pages = this.pages.filter(item => item._id !== id)
this.$nuxt.refresh();
})
.catch(err => {
if (err.response.status === 401) {
return this.$message({
type: 'error',
message: 'لطفا دوباره وارد سیستم شوید.'
})
}
if (err.response.status === 403) {
return this.$message({
type: 'error',
message: err.response.data.message
})
}
if (err.response.status === 422) {
return this.$message({
type: 'error',
message: err.response.data.message
})
}
console.log(err.response.data)
})
}).catch(() => {
this.$message({
type: 'warning',
message: 'عملیات لغو شد'
})
})
}
},
head() {
return {
title: this.title
}
},
layout: 'admin',
async asyncData({$axios, error}) {
try {
const category = await $axios.get(`/api/admin/category`);
return {
pages: category.data
}
} catch (e) {
if (e?.response?.status === 401) {
error({status: 401, message: 'شما اجازه دسترسی به این صفحه را ندارید'})
} else {
error({status: 500, message: 'there is a problem here'})
}
}
}
}
</script>
+265
View File
@@ -0,0 +1,265 @@
<template>
<div class="centered-container">
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">
بارگذاری عملکرد PDF
</CBreadcrumb>
</CustomSubHeader>
<CCard class="upload-card">
<CCardHeader>
<slot name="header">
<i class="fal fa-upload"></i>
<span class="header-title">بارگذاری عملکرد</span>
</slot>
</CCardHeader>
<CCardBody>
<CRow>
<CCol md="12" class="text-center">
<div class="upload-container">
<el-upload
ref="upload"
class="upload-demo"
drag
action="/api/admin/pdf-manager/add"
:headers="uploadHeaders"
:data="uploadData"
:before-upload="beforeUpload"
:on-success="handleSuccess"
:on-error="handleError"
:on-change="handleChange"
:limit="1"
accept=".pdf"
:file-list="fileList"
:auto-upload="false">
<i class="el-icon-upload"></i>
<div class="upload-text">
فایل PDF خود را به اینجا بکشید یا
<br />
<em>برای بارگذاری کلیک کنید</em>
</div>
</el-upload>
<el-input
v-model="title"
placeholder="عنوان را وارد کنید"
class="mt-3" />
<el-button
:loading="uploading"
@click="submitUpload"
size="small"
class="mt-3 upload-button"
type="primary"
icon="el-icon-upload2">
بارگذاری
</el-button>
</div>
</CCol>
</CRow>
</CCardBody>
</CCard>
<CCard class="pdf-list-card mt-4">
<CCardHeader>
<h5>PDF های بارگذاری شده</h5>
</CCardHeader>
<CCardBody>
<CRow>
<CCol md="12">
<div v-if="pdfs.length > 0" class="pdf-list">
<el-table
:data="pdfs"
class="pdf-table"
stripe>
<el-table-column
prop="title"
label="عنوان"
width="70%">
</el-table-column>
<el-table-column
label="اقدامات"
width="30%">
<template v-slot="scope">
<el-button
size="small"
type="danger"
icon="el-icon-delete"
@click="deletePDF(scope.row.id)">
حذف
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div v-else class="text-center">
<p>هنوز پی دی افی بارگذاری نشده است.</p>
</div>
</CCol>
</CRow>
</CCardBody>
</CCard>
</div>
</template>
<script>
export default {
data() {
return {
title: "",
fileList: [],
uploading: false,
token: null,
pdfs: [], // List of uploaded PDFs
};
},
computed: {
uploadData() {
return {
title: this.title,
};
},
uploadHeaders() {
return {
Authorization: `Bearer ${this.token}`,
};
},
},
mounted() {
if (typeof window !== "undefined") {
this.token = localStorage.getItem(
"auth._token.local"
);
}
this.fetchPDFs(); // Fetch the PDFs on component mount
},
layout: "admin",
methods: {
fetchPDFs() {
this.$axios
.get("/api/admin/books", {
headers: this.uploadHeaders,
})
.then((response) => {
this.pdfs = response.data;
})
.catch((error) => {
console.error("Error fetching PDFs:", error);
this.$message.error(
"خطا در بارگذاری لیست PDF ها"
);
});
},
beforeUpload(file) {
const isPDF = file.type === "application/pdf";
if (!isPDF) {
this.$message.error(
"فقط فایل های با فرمت پی دی اف مجاز است"
);
}
return isPDF;
},
handleChange(file, fileList) {
this.fileList = fileList;
console.log("File list updated:", fileList);
},
handleSuccess(response, file, fileList) {
this.uploading = false;
this.fileList = fileList; // Ensure fileList is updated
this.$message.success(
"پی دی اف با موفقیت بارگزاری شد"
);
this.fetchPDFs(); // Refresh the list of PDFs
},
handleError(err, file, fileList) {
this.uploading = false;
this.$message.error("خطا در آپلود");
},
submitUpload() {
if (this.fileList.length === 0) {
this.$message.warning(
"لطفاً یک فایل را انتخاب کنید"
);
return;
}
if (this.$refs.upload) {
this.uploading = true;
this.$refs.upload.submit();
} else {
console.error("Upload reference is not defined");
}
},
deletePDF(id) {
this.$axios
.delete(`/api/admin/book/${id}`, {
headers: this.uploadHeaders,
})
.then(() => {
this.$message.success(
"پی دی اف با موفقیت حذف شد"
);
this.fetchPDFs(); // Refresh the list of PDFs after deletion
})
.catch((error) => {
console.error("Error deleting PDF:", error);
this.$message.error("خطا در حذف پی دی اف");
});
},
},
};
</script>
<style scoped>
.centered-container {
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
width: 100%;
}
.upload-card,
.pdf-list-card {
width: 100%;
max-width: 800px;
}
.header-title {
color: #000;
}
.upload-container {
display: flex;
flex-direction: column;
align-items: center;
max-width: 600px;
width: 100%;
}
.upload-demo {
border: 2px dashed #dcdfe6;
border-radius: 4px;
padding: 20px;
width: 100%;
text-align: center;
background: #f9f9f9;
}
.upload-text {
font-size: 16px;
color: #606266;
}
.upload-button {
width: auto;
margin-top: 20px;
}
.pdf-list {
margin-top: 20px;
}
.pdf-table {
width: 100%;
}
</style>
+468
View File
@@ -0,0 +1,468 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="primary" class="mr-auto" :to="{ name: 'admin-polls',query: {page: 1} }">برگشت به صفحه قبل</CButton>
<CButton v-if="$route.params.details === 'new'" size="sm" color="success" class="mr-1" @click="post">افزودن</CButton>
<CButton v-else size="sm" color="success" class="mr-1" @click="update">بروزرسانی</CButton>
</CustomSubHeader>
<CRow style="display : flex ; flex-direction: column">
<CRow>
<CCol lg="6">
<CCard>
<CCardBody>
<CRow>
<CCol sm="12">
<CInput
label="عنوان"
:class="validation.title ? 'err' : null"
:description="validation.title ? validation.title.msg : null"
v-model="poll.title"
/>
</CCol>
<CCol sm="12">
<CTextarea
:class="validation.description ? 'err' : null"
label="توضیحات"
:description="validation.description ? validation.description.msg : null"
v-model="poll.description"
/>
</CCol>
<el-divider></el-divider>
<CCol sm="12">
<h6>تاریخ شروع</h6>
<date-picker format="YYYY-MM-DD" display-format="jMMMM jD" v-model="poll.startDate"></date-picker>
<p class="text-danger" v-if="validation.startDate">{{ validation.startDate.msg }}</p>
</CCol>
<CCol sm="12" class="mt-3">
<h6>تاریخ پایان</h6>
<date-picker format="YYYY-MM-DD" display-format="jMMMM jD" v-model="poll.endDate"></date-picker>
<p class="text-danger" v-if="validation.endDate">{{ validation.endDate.msg }}</p>
</CCol>
</CRow>
</CCardBody>
</CCard>
</CCol>
<CCol lg="6">
<CCard>
<CCardBody>
<CCol sm="12">
<h6>{{ this.$route.params.details !== "new" ? "دسته بندی" : "انتخاب دسته بندی" }}</h6>
<el-select
filterable
clearable
style="width : 100%"
v-model="catId"
placeholder="انتخاب دسته بندی">
<el-option
v-for="item in categories"
v-if="availableCategory(item._id)"
:key="item._id"
:label="item.title"
:value="item._id"
>
<!-- <span>{{setTitle(item)}}</span> -->
</el-option>
</el-select>
<p style="margin-top : 5px !important ; color : red" class="form-err" v-if="validation.catId">{{ validation.catId.msg }}</p>
</CCol>
<el-divider></el-divider>
<CCol sm="12">
<h6>نوع گزینه ها</h6>
<el-select
style="width : 100%"
v-model="poll.surveyType"
placeholder="انتخاب نوع">
<el-option label="انتخاب چند گزینه همزمان" value="check"/>
<el-option label="فقط انتخاب یک گزینه" value="radio"/>
</el-select>
<p style="margin-top : 5px !important ; color : red" class="form-err" v-if="validation.surveyType">{{ validation.surveyType.msg }}</p>
</CCol>
<el-divider></el-divider>
<el-checkbox label="منتشر شود" v-model="poll.publish"/>
</CCardBody>
</CCard>
</CCol>
<CCol sm="12">
<CCard>
<CCardBody>
<CRow>
<CCol lg="6">
<h6>لیست گزینه ها</h6>
<el-divider></el-divider>
<el-table
style="width: 100%;"
:data="poll.options"
>
<el-table-column
type="index"
label="#"
>
</el-table-column>
<el-table-column
label="گزینه ها"
>
<template slot-scope="scope">
{{ scope.row }}
</template>
</el-table-column>
<el-table-column
label="ویرایش"
width="65"
>
<template slot-scope="scope">
<CButton color="danger" variant="outline" :key="scope.row" @click="removeOption(scope.row)">
<i class="far fa-trash-alt"></i>
</CButton>
</template>
</el-table-column>
</el-table>
<p class="text-danger" v-if="validation.options">{{ validation.options.msg }}</p>
</CCol>
<CCol lg="6">
<h6>افزودن گزینه</h6>
<el-divider></el-divider>
<el-input v-model="newOption"/>
<br>
<br>
<el-button type="success" @click="addOption">افروزدن</el-button>
<p style="margin-top : 5px !important ; color : red" class="form-err" v-if="validation.newOption">{{ validation.newOption.msg }}</p>
</CCol>
</CRow>
</CCardBody>
</CCard>
</CCol>
<CCol sm="12" v-if="$route.params.details !== 'new'">
<CCard>
<CCardBody>
<h6>جواب ها</h6>
<el-divider></el-divider>
<div class="survey-item2" v-for="(item, index) in poll.options" :key="index">
<h4>{{ item }}</h4>
<el-progress :percentage="progress(item)" style="direction: rtl" color="#CC0000"></el-progress>
</div>
</CCardBody>
</CCard>
</CCol>
</CRow>
</CRow>
</div>
</template>
<script>
export default {
data() {
return {
poll: null,
categories: null,
validation: {},
newOption: ''
}
},
computed: {
title() {
return this.$route.params.details === "new" ? "افزودن نظرسنجی جدید" : "مشاهده نظرسنجی"
},
catId: {
get() {
if (this.$route.params.details === 'new') {
return this.poll.catId
} else {
return this.poll.catId._id
}
},
set(value) {
if (this.$route.params.details === 'new') {
this.poll.catId = value
} else {
this.poll.catId._id = value
}
}
}
},
methods: {
progress(answerItem) {
let filteredAnswers = this.poll.answers.filter(item0 => this.poll.options.includes(item0))
let num = filteredAnswers.filter(item1 => item1 === answerItem).length
return Number(((num * 100 / filteredAnswers.length) || 0).toFixed(0))
},
addOption() {
this.validation = {}
if (!this.newOption) return this.validation = {
newOption: {
msg: 'ابتدا گزینه را بنویسید'
}
}
if (this.poll.options.includes(this.newOption)) return this.validation = {
newOption: {
msg: 'این گزینه قبلا اضافه شده'
}
}
this.poll.options.push(this.newOption)
this.newOption = ''
if (this.$route.params.details === 'new') {
this.$message({
type: 'success',
message: 'گزینه افزوده شد'
})
} else {
this.$message({
type: 'warning',
message: 'تا زمانی که دکمه بروزرسانی بالای صفحه رو نزنید گزینه ها افزوده نمیشوند'
})
}
},
removeOption(target) {
this.$confirm("گزینه حذف شود؟", "اخطار", {
confirmButtonText: "بله",
cancelButtonText: "لغو",
type: "warning",
})
.then(() => {
this.poll.options = this.poll.options.filter(item => item !== target)
if (this.$route.params.details === 'new') {
this.$message({
type: 'success',
message: 'گزینه حذف شد'
})
} else {
this.$message({
type: 'warning',
message: 'تا زمانی که دکمه بروزرسانی بالای صفحه رو نزنید تغییرات اعمال نمیشوند'
})
}
})
.catch(() => {
this.$message({
type: "warning",
message: "عملیات لغو شد"
})
})
},
availableCategory(id) {
return this.$auth.user.permissions.includes('superAdmin') || this.$auth.user.specialPermissions.includes(id)
},
post() {
this.validation = {}
this.$axios
.post(`/api/admin/poll`, this.poll)
.then((response) => {
this.$message({
type: "success",
message: "نظرسنجی با موفقیت ایجاد شد."
})
this.$router.push({name: "admin-polls"})
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید."
})
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message
})
}
if (err.response.status === 500) {
return this.$message({
type: "error",
message: "مشکلی در ارسال درخواست پیش آمده"
})
}
if (err.response.status === 422) {
this.validation = err.response.data.validation
this.$message({
type: 'warning',
message: 'پارامترها رو بررسی کنید'
})
} else console.log(err.response.data)
})
},
update() {
this.validation = {}
this.$axios
.put(`/api/admin/poll/${this.poll._id}`, {...this.poll, catId: this.poll.catId._id})
.then((response) => {
this.$message({
type: "success",
message: "اطلاعات بروزرسانی شد."
})
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید."
})
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message
})
}
if (err.response.status === 500) {
return this.$message({
type: "error",
message: "مشکلی در ارسال درخواست پیش آمده"
})
}
if (err.response.status === 422) {
this.validation = err.response.data.validation
this.$message({
type: 'warning',
message: 'پارامترها رو بررسی کنید'
})
} else console.log(err.response.data)
});
},
},
head() {
return {
title: this.title,
}
},
layout: "admin",
async asyncData({$axios, params, error}) {
try {
const categories = await $axios.get('/api/admin/category/getParent')
if (params.details !== 'new') {
const poll = await $axios.get(`/api/admin/poll/${params.details}`)
return {
categories: categories.data,
poll: poll.data
}
} else {
return {
categories: categories.data,
poll: {
title: '',
description: '',
surveyType: '',
catId: '',
options: [],
startDate: '',
endDate: '',
publish: true
}
}
}
} catch (e) {
if (e?.response?.status === 401) error({status: 401, message: "لطفا دوباره وارد سیستم شوید."})
if (e?.response?.status === 403) error({status: 403, message: e?.response?.data?.message})
if (e?.response?.status === 500) error({status: 500, message: "مشکلی در گرفتن اطلاعات پیش آمده"})
else error({status: 404, message: "پرونده خبری مورد نظر پیدا نشد"})
}
},
}
</script>
<style lang="scss">
.survey-item2 {
padding: 20px 0;
.el-radio-group {
direction: ltr;
.el-radio__input.is-checked .el-radio__inner {
background: red;
border-color: red;
}
.el-radio__input.is-checked + .el-radio__label {
color: red;
}
.el-radio__label {
&:hover {
color: red;
}
}
.el-radio__inner {
border: 1px solid #666666;
}
.el-radio__inner:hover {
border-color: red;
}
}
.comment-btn {
display: flex;
justify-content: flex-end;
button {
&:disabled {
border-color: #666666;
background-color: #666666;
color: white;
border-radius: 5px;
}
}
}
.el-checkbox-group {
direction: ltr;
text-align: right;
.el-checkbox__inner {
border: 1px solid #666666;
&:hover {
border-color: red;
}
}
}
.el-checkbox__input.is-checked .el-checkbox__inner, .el-checkbox__input.is-indeterminate .el-checkbox__inner {
background-color: red;
border-color: red;
}
.el-checkbox__label {
&:hover {
color: red;
}
}
.el-checkbox__input.is-checked + .el-checkbox__label {
color: red;
}
.el-progress {
font-family: 'sansNum', sans-serif;
.el-progress-bar__inner {
right: 0;
}
.el-progress__text {
margin-right: 10px;
}
}
}
</style>
+289
View File
@@ -0,0 +1,289 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="success" :to="{ name: 'admin-polls-details', params: { details: 'new' } }" class="mr-auto">افزودن</CButton>
</CustomSubHeader>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-filter"></i>
<span style="color:#000">فیلتر</span>
</slot>
</CCardHeader>
<CCardBody>
<CRow>
<CCol md="6">
<CRow style="flex-direction : column;">
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>عنوان</span>
</CCol>
<CCol col="md-9">
<el-input style="width : 100%" placeholder="" v-model="search.term"></el-input>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>تاریخ</span>
</CCol>
<CCol col="md-9">
<date-picker range clearable format="YYYY-MM-DD" display-format="jMMMM jD" v-model="search.date"></date-picker>
</CCol>
</CRow>
</CCol>
</CRow>
</CCol>
<CCol md="6">
<CRow style="flex-direction : column;">
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>وضعیت نمایش</span>
</CCol>
<CCol col="md-9">
<el-select v-model="search.publish" clearable style="width : 100%" placeholder="">
<el-option :key="true" label="نمایش داده شود" :value="true">
</el-option>
<el-option :key="false" label="نمایش داده نشود" :value="false">
</el-option>
</el-select>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>دسته بندی</span>
</CCol>
<CCol col="md-9">
<el-select filterable clearable style="width : 100%" v-model="search.catId"
placeholder="انتخاب دسته بندی">
<el-option v-for="item in parents" :key="item._id" :label="item.title" :value="item._id"/>
</el-select>
</CCol>
</CRow>
</CCol>
</CRow>
</CCol>
</CRow>
<CRow>
<el-button :loading="loading" @click="handleSearch" size="small" style="width: auto;margin: 25px auto auto auto;" type="primary" icon="el-icon-search">جست و جو</el-button>
</CRow>
</CCardBody>
</CCard>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>{{ list_title }}</span>
</slot>
<slot></slot>
</CCardHeader>
<CCardBody>
<el-table
v-loading="loading"
:data="polls.docs"
:default-sort="{ prop: 'date', order: 'descending' }"
style="width: 100%"
>
<el-table-column type="index" label="#"></el-table-column>
<el-table-column label="عنوان">
<template slot-scope="scope">
<span class="title">
<el-popover placement="top-end" trigger="hover" :content="scope.row.title">
<i v-if="scope.row.title.length > 25" class="el-icon-info" slot="reference"></i>
</el-popover>
{{ scope.row.title }}
</span>
</template>
</el-table-column>
<el-table-column
prop="catId.title"
label="دسته بندی"
width="">
</el-table-column>
<el-table-column
label="تاریخ شروع"
width=""
>
<template slot-scope="scope">
<span>{{ jDate(scope.row.startDate) }}</span>
</template>
</el-table-column>
<el-table-column
label="تاریخ پایان"
width=""
>
<template slot-scope="scope">
<span>{{ jDate(scope.row.endDate) }}</span>
</template>
</el-table-column>
<el-table-column label="ویرایش" width="110" align="center">
<template slot-scope="scope">
<CButton color="danger" variant="outline" :key="scope.row._id + Math.random()" @click="deletePoll(scope.row._id)">
<i class="far fa-trash-alt"></i>
</CButton>
<CButton color="success" variant="outline" :key="scope.row._id" :to="{ name: 'admin-polls-details',params: { details: scope.row._id } }">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
<CCard class="col" v-if="polls.totalDocs>5">
<CRow alignHorizontal="center" style="padding : 10px">
<el-pagination :hide-on-single-page="true" layout="prev, pager, next" :page-size="polls.limit"
@current-change="handleCurrentChange" :current-page.sync="polls.page" :total="polls.totalDocs">
</el-pagination>
</CRow>
</CCard>
</div>
</template>
<script>
import moment from "moment-jalaali"
export default {
data() {
return {
title: "لیست نظرسنجی ها",
list_title: "لیست",
polls: null,
search: {},
parent: null,
loading: false
};
},
computed: {
pageQuery() {
return this.$route.query.page;
}
},
watch: {
pageQuery(newPage, oldPage) {
this.$nuxt.refresh()
}
},
methods: {
jDate(date) {
return moment(date).format("jYYYY/jMM/jDD")
},
deletePoll(id) {
this.$confirm("نظرسنجی حذف شود؟", "اخطار", {
confirmButtonText: "بله",
cancelButtonText: "لغو",
type: "warning"
})
.then(async () => {
this.$axios
.delete(`/api/admin/poll/${id}`)
.then((res) => {
this.$message({
type: "success",
message: "نظرسنجی با موفقیت حذف شد"
})
this.polls.docs = this.polls.docs.filter(item => item._id !== id)
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید."
})
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message
})
}
if (err.response.status === 422) {
return this.$message({
type: "error",
message: err.response.data.message
})
}
console.log(err.response.data)
})
})
.catch(() => {
this.$message({
type: "warning",
message: "عملیات لغو شد",
})
})
},
handleCurrentChange(page) {
this.handleSearch(page);
},
handleSearch(page) {
this.loading = true;
const data = {
term: this.search.term,
catId: this.search.catId,
showInHome: this.search.showInHome
}
this.$axios.post(`/api/admin/poll/search?page=${page}`, data, this.axiosConfig)
.then((result) => {
this.polls = result.data;
this.loading = false;
})
.catch(err => {
this.loading = false;
if (err.response.status === 401) {
return this.$message({
type: 'error',
message: 'لطفا دوباره وارد سیستم شوید.'
})
}
if (err.response.status === 422) this.validation = err.response.data.validation
else console.log(err.response.data)
})
}
},
head() {
return {
title: this.title
}
},
layout: "admin",
async asyncData({$axios, query, error}) {
try {
const requests = [
$axios.get(`/api/admin/poll?page=${query.page}`),
$axios.get("/api/admin/category/getParent")
]
const fetch = await Promise.all(requests)
let [polls, parents] = fetch
return {
polls: polls.data,
parents: parents.data
}
} catch (e) {
if (e?.response?.status === 401) error({status: 401, message: 'شما اجازه دسترسی به این صفحه را ندارید'})
else error({status: 500, message: "مشکلی در گرفتن اطلاعات بوجود آمده است"})
}
}
}
</script>
+382
View File
@@ -0,0 +1,382 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="primary" class="mr-auto" :to="{ name: 'admin-slider' }">برگشت به صفحه قبل</CButton>
<CButton v-if="$route.params.details === 'new'" size="sm" color="success" class="mr-1" @click="post">افزودن
</CButton>
<CButton v-else size="sm" color="success" class="mr-1" @click="update">بروزرسانی</CButton>
</CustomSubHeader>
<CRow style="display : flex ; flex-direction: column">
<CRow>
<CCol lg="6">
<CCard>
<CCardBody>
<CCol sm="12">
<h6>
قسمت انتخابی
<i v-c-tooltip="
'شما باید تعیین کنید که این خبر برای کدام قسمت پرتال می باشد'
" class="fas fa-question-circle"></i>
</h6>
<el-select :disabled="$auth.user.portals.length === 1" v-model="slider.modelType"
placeholder="انتخاب کنید" style="width: 100%;">
<el-option v-for="item in portals" :key="item.value" :label="item.name" :value="item.value">
</el-option>
</el-select>
<p style="margin-top : 5px !important ; color : red" class="form-err" v-if="validation.modelType">
{{ validation.modelType.msg }}
</p>
</CCol>
<el-divider></el-divider>
<CCol sm="12">
<CTextarea :class="validation.title ? 'err' : null" label="عنوان" :description="
validation.title ? validation.title.msg : null
" v-model="slider.title" />
</CCol>
<el-divider></el-divider>
<CCol sm="12">
<CTextarea :class="validation.summaryTitle ? 'err' : null" label="عنوان خلاصه" :description="
validation.summaryTitle ? validation.title.msg : null
" v-model="slider.summaryTitle" />
</CCol>
</CCardBody>
</CCard>
</CCol>
<CCol lg="6">
<CCard>
<CCardBody>
<CCol sm="12">
<el-checkbox v-model="slider.isLocal" @change="changeBox"
label="انتخاب خبر از داخل پرتال" />
</CCol>
<el-divider></el-divider>
<CCol sm="12">
<NuxtLink class="btn btn-light" v-if="slider.isLocal" :to="{name: 'portal-news-details', params: {portal: slider.modelType,details: slider.url}}">نمایش خبر</NuxtLink>
<CInput v-else :class="validation.url ? 'err' : null" :label="slider.isLocal ? 'عنوان خبر' : 'لینک'" :description="
validation.url ? validation.url.msg : null
" v-model="slider.url" />
</CCol>
<el-divider></el-divider>
<CCol sm="12">
<h6 class="mt-2">ترتیب نمایش</h6>
<!-- <el-input-number style="width:100%" class="mt-2" size="mini" v-model="slider.index"-->
<!-- controls-position="right" :min="0"></el-input-number>-->
<el-select style="width:100%" class="mt-2" v-model="slider.index" placeholder="">
<el-option
v-for="item in allSlider.length + 10"
v-if="!allSlider.find((item2) => item2.index === item)"
:key="item"
:label="item"
:value="item">
</el-option>
</el-select>
</CCol>
</CCardBody>
</CCard>
</CCol>
</CRow>
<CRow>
<CCol>
<CCard>
<CCardBody>
<CCol sm="12">
<h5>کاور</h5>
<el-divider />
<CCol>
<img :src="slider.cover" style="width: 100%;" alt="" />
</CCol>
<input type="file" ref="cover" @change="imagePreview" />
<p style="margin-top : 5px !important ;" class="form-err" v-if="validation.cover">
{{ validation.cover.msg }}
</p>
<p class="mt-3 text-muted">
عکس 600*400 باشد. در غیر این صورت اتوماتیک بریده می شود.
</p>
</CCol>
</CCardBody>
</CCard>
</CCol>
</CRow>
</CRow>
<el-dialog title="انتخاب خبر" close="closeModal" :before-close="closeModal" :visible.sync="showGetNews">
<CContainer style="border: solid 1px;padding: 25px;border-radius: 15px;">
<CRow style="flex-direction: column;">
<CCol>
<template style="text-align: justify; word-break: break-word;">
<el-select style="width : 100%" v-model="slider.url" filterable remote reserve-keyword placeholder="بخشی از تیتر خبر را وارد کنید"
:remote-method="remoteMethod" :loading="loading">
<el-option v-for="item in news" :key="item._id" :label="item.title" :value="item._id">
</el-option>
</el-select>
</template>
</CCol>
<CCol>
<template style="text-align: justify; word-break: break-word;">
<el-button @click="handleClick" size="small" style="width: auto;margin: 25px auto auto auto;" type="primary">
تایید</el-button>
</template>
</CCol>
</CRow>
</CContainer>
</el-dialog>
</div>
</template>
<script>
import axiosUploadProcess from "@/mixins/axiosUploadProcess";
export default {
data() {
return {
slider: null,
typePage: true,
validation: {},
editorConfig: {
language: "en",
extraPlugins: ["bidi", "justify"],
},
portals: null,
showGetNews: false,
loading : false,
news : [],
baseUrl : 'http://localhost:6688',
allSlider : null
};
},
mixins: [axiosUploadProcess],
computed: {
title() {
return this.$route.params.details === "new" ?
"افزودن اسلایدر جدید" :
"مشاهده جزئیات اسلایدر";
},
customUrl:{
get:()=>{
return this.slider?.url?.title
},
set:(value)=>{
this.slider.url = value
}
}
},
methods: {
imagePreview(e) {
this.slider.cover = URL.createObjectURL(e.target.files[0]);
},
changeBox(){
this.slider.url = null;
this.showGetNews = this.slider.isLocal;
},
closeModal(done) {
this.slider.isLocal = false;
this.slider.url = null;
done();
},
handleClick(){
this.showGetNews = false;
},
remoteMethod(query) {
this.loading = true;
this.$axios(`/api/public/searchnewsbytitle/${query}`)
.then((news) => {
this.loading = false;
this.news = news.data;
})
.catch((err) => {
this.loading = false;
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
if (err.response.status === 500) {
return this.$message({
type: "error",
message: "مشکلی در ارسال درخواست پیش آمده",
});
}
if (err.response.status === 422)
this.validation = err.response.data.validation;
else console.log(err.response.data);
})
},
post() {
this.validation = {};
const data = new FormData();
data.append("title", this.slider.title.trim());
data.append("summaryTitle", this.slider.summaryTitle.trim());
data.append("url", this.slider?.url?.trim())
data.append("index", this.slider.index);
data.append("modelType", this.slider.modelType);
data.append("isLocal", this.slider.isLocal);
if (this.$refs.cover.files[0])
data.append("cover", this.$refs.cover.files[0]);
this.$axios
.post(`/api/admin/slider`, data, this.axiosConfig)
.then((response) => {
this.$message({
type: "success",
message: "اسلایدر با موفقیت ایجاد شد.",
});
this.$router.push({
name: "admin-slider",
});
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
if (err.response.status === 500) {
return this.$message({
type: "error",
message: "مشکلی در ارسال درخواست پیش آمده",
});
}
if (err.response.status === 422)
this.validation = err.response.data.validation;
else console.log(err.response.data);
});
},
update() {
this.validation = {};
const data = new FormData();
data.append("title", this.slider.title.trim());
data.append("summaryTitle", this.slider.summaryTitle.trim());
data.append("url", this.slider?.url?.trim());
data.append("index", this.slider.index);
data.append("modelType", this.slider.modelType);
data.append("isLocal", this.slider.isLocal);
if (this.$refs.cover.files[0])
data.append("cover", this.$refs.cover.files[0]);
this.$axios
.put(`/api/admin/slider/${this.slider._id}`, data, this.axiosConfig)
.then((response) => {
this.$message({
type: "success",
message: "اطلاعات بروزرسانی شد.",
});
this.$nuxt.refresh();
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
if (err.response.status === 500) {
return this.$message({
type: "error",
message: "مشکلی در ارسال درخواست پیش آمده",
});
}
if (err.response.status === 422)
this.validation = err.response.data.validation;
else console.log(err.response.data);
});
},
},
head() {
return {
title: this.title,
};
},
layout: "admin",
async asyncData({$axios, $auth, params, query, error}) {
try {
// const portals = await $axios.get("/api/admin/portals" ,{ progress: false });
// const allSlider = await $axios.get(`/api/admin/slider` ,{ progress: false });
const requests = [
$axios.get("/api/admin/portals" ,{ progress: false }),
$axios.get(`/api/admin/slider` ,{ progress: false })
];
const fetch = await Promise.all(requests);
let [portals, allSlider] = fetch;
let setModelType = $auth.user.portals.length !== 1 ?
$auth.user.portals :
$auth.user.portals[0];
if (params.details !== "new") {
const slider = await $axios.get(`/api/admin/slider/${params.details}`);
return {
portals: portals.data,
allSlider : allSlider.data,
slider: slider.data
};
} else {
return {
portals: portals.data,
allSlider : allSlider.data,
slider: {
title: '',
summaryTitle: '',
isLocal: false,
url: '',
index: null,
siteMap: true,
modelType: setModelType,
},
};
}
} catch (e) {
if (e?.response?.status === 401) {
error({
status: 401,
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (e?.response?.status === 403) {
error({
status: 403,
message: e?.response?.data?.message,
});
}
if (e?.response?.status === 500) {
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات پیش آمده",
});
} else
error({
status: 404,
message: "اسلایدر مورد نظر پیدا نشد",
});
}
},
};
</script>
+204
View File
@@ -0,0 +1,204 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="success" :to="{ name: 'admin-slider-details', params: { details: 'new' } }"
class="mr-auto">افزودن</CButton>
</CustomSubHeader>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-filter"></i>
<span style="color:#000">فیلتر</span>
</slot>
</CCardHeader>
<CCardBody>
<CRow>
<CCol class="col">
<CRow>
<el-input v-model="search" size="medium" placeholder="جستجو" />
</CRow>
</CCol>
</CRow>
</CCardBody>
</CCard>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>{{ list_title }}</span>
</slot>
<slot> </slot>
</CCardHeader>
<CCardBody>
<el-table :data="filteredSlider" :default-sort="{ prop: 'date', order: 'descending' }" style="width: 100%">
<el-table-column type="index" label="#"> </el-table-column>
<el-table-column
label="عکس اسلایدر"
width="">
<template slot-scope="scope">
<img height="130px" :src="scope.row.cover || '/img/avatar.png'" :alt="scope.row.icon">
</template>
</el-table-column>
<el-table-column label="تیتر" width="180px">
<template slot-scope="scope">
<span style="height: 0px; display: ruby-base;">
<el-popover placement="top-end" trigger="hover" :content="scope.row.title">
<i v-if="scope.row.title.length > 25" class="el-icon-info" slot="reference"></i>
</el-popover>
{{ scope.row.title }}
</span>
</template>
</el-table-column>
<el-table-column label="قسمت">
<template slot-scope="scope">
<el-tag class="flagType" style="width: 80px;
text-align: center;">{{scope.row.modelType === 'ostandari' ? 'استانداری' : 'ستاد انتخابات'}}</el-tag>
</template>
</el-table-column>
<el-table-column label="تاریخ ایجاد" width="">
<template slot-scope="scope">
<span>{{ jDate(scope.row.created_at) }}</span>
</template>
</el-table-column>
<el-table-column label="ویرایش" width="110" align="center">
<template slot-scope="scope">
<CButton color="danger" variant="outline" :key="scope.row._id + Math.random()"
@click="deleteSlider(scope.row._id)">
<i class="far fa-trash-alt"></i>
</CButton>
<CButton color="success" variant="outline" :key="scope.row._id" :to="{
name: 'admin-slider-details',
params: { details: scope.row._id },
}">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
<CCard class="col" v-if="!search && slider.length>10">
<CRow alignHorizontal="center" style="padding : 10px">
<el-pagination :hide-on-single-page="true" layout="prev, pager, next" :page-size="10"
:current-page.sync="curentPage" :total="slider.length">
</el-pagination>
</CRow>
</CCard>
</div>
</template>
<script>
import moment from "moment-jalaali";
export default {
data() {
return {
title: "لیست اسلایدر",
list_title: "لیست",
slider: null,
search: "",
curentPage: 1,
skip: 0
};
},
computed: {
filteredSlider() {
if (this.search) {
return this.slider.filter(
(data) =>
data.title.toLowerCase().includes(this.search.toLowerCase())
);
} else {
return this.slider.slice((this.curentPage - 1) * 10, this.curentPage * 10);
}
},
},
methods: {
jDate(date) {
return moment(date).format("jYYYY/jMM/jDD");
},
deleteSlider(id) {
this.$confirm("اسلایدر حذف شود؟", "هشدار", {
confirmButtonText: "بله",
cancelButtonText: "لغو",
type: "warning",
})
.then(async () => {
this.$axios
.delete(`/api/admin/slider/${id}`)
.then((res) => {
this.$message({
type: "success",
message: "اسلایدر با موفقیت حذف شد",
});
this.slider = this.slider.filter((item) => item._id !== id);
})
.catch((err) => {
if (err.response.status === 401) {
return this.$message({
type: "error",
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (err.response.status === 403) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
if (err.response.status === 422) {
return this.$message({
type: "error",
message: err.response.data.message,
});
}
console.log(err.response.data);
});
})
.catch(() => {
this.$message({
type: "warning",
message: "عملیات لغو شد",
});
});
},
},
head() {
return {
title: this.title,
};
},
layout: "admin",
async asyncData({
$axios,
error
}) {
try {
const slider = await $axios.get(`/api/admin/slider`);
return {
slider: slider.data,
};
} catch (e) {
if(e?.response?.status === 401){
error({
status: 401,
message: 'شما اجازه دسترسی به این صفحه را ندارید'
})
}else{
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات بوجود آمده است",
});
}
}
},
};
</script>
+129
View File
@@ -0,0 +1,129 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="success" class="mr-auto" @click="update">بروزرسانی</CButton>
</CustomSubHeader>
<CCard>
<CCardBody>
<CRow>
<CCol xxl="3">
<h4>ایمیل</h4>
<el-divider></el-divider>
<el-checkbox label="نمایش آیکون ایمیل در فوتر سایت" v-model="yearBanner.hasEmail"/>
<br>
<el-input v-model="yearBanner.email" placeholder="آدرس ایمیل را وارد کنید"/>
</CCol>
<CCol xxl="3" class="mt-5 mt-xxl-0">
<h4>گوگل پلاس</h4>
<el-divider></el-divider>
<el-checkbox label="نمایش آیکون گوگل پلاس در فوتر سایت" v-model="yearBanner.hasGPlus"/>
<br>
<el-input v-model="yearBanner.gPlus" placeholder="url گوگل پلاس را وارد کنید"/>
</CCol>
<CCol xxl="3" class="mt-5 mt-xxl-0">
<h4>توییتر</h4>
<el-divider></el-divider>
<el-checkbox label="نمایش آیکون توییتر در فوتر سایت" v-model="yearBanner.hasTweeter"/>
<br>
<el-input v-model="yearBanner.tweeter" placeholder="url توییتر را وارد کنید"/>
</CCol>
<CCol xxl="3" class="mt-5 mt-xxl-0">
<h4>اینستاگرام</h4>
<el-divider></el-divider>
<el-checkbox label="نمایش آیکون اینستاگرام در فوتر سایت" v-model="yearBanner.hasInstagram"/>
<br>
<el-input v-model="yearBanner.instagram" placeholder="url اینستاگرام را وارد کنید"/>
</CCol>
</CRow>
</CCardBody>
</CCard>
</div>
</template>
<script>
export default {
data() {
return {
title: 'مدیریت آدرس ایمیل و شبکه های اجتماعی',
yearBanner: null,
}
},
methods: {
update() {
this.validation = {}
const data = {
iranFlag: this.yearBanner.iranFlag,
electionBtn: this.yearBanner.electionBtn,
// socialLinks
hasEmail: this.yearBanner.hasEmail,
hasGPlus: this.yearBanner.hasGPlus,
hasTweeter: this.yearBanner.hasTweeter,
hasInstagram: this.yearBanner.hasInstagram,
email: this.yearBanner.email,
gPlus: this.yearBanner.gPlus,
tweeter: this.yearBanner.tweeter,
instagram: this.yearBanner.instagram,
}
this.$axios.post('/api/admin/yearBanner', data)
.then(res => {
this.$message({
type: 'success',
message: 'تغییرات با موفقیت انجام شد'
})
})
.catch(err => {
if (err.response?.status === 422) {
this.validations = err.response.data.validation
this.$message({
type: 'warning',
message: 'پارامترها را بررسی کنید'
})
} else console.log(e)
})
}
},
head() {
return {
title: this.title,
};
},
layout: "admin",
async asyncData({$axios, error}) {
try {
const yearBanner = await $axios.get('/api/public/yearBanner')
return {
yearBanner: yearBanner.data
}
} catch (e) {
if (e?.response?.status === 401) {
error({
status: 401,
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (e?.response?.status === 403) {
error({
status: 403,
message: e?.response?.data?.message,
});
}
if (e?.response?.status === 500) {
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات پیش آمده",
});
} else
error({
status: 404,
message: "اسلایدر مورد نظر پیدا نشد",
});
}
},
}
</script>
+584
View File
@@ -0,0 +1,584 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton
size="sm"
color="primary"
class="mr-auto"
:to="{ name: 'admin-users' }"
>برگشت به صفحه قبل
</CButton
>
<CButton
v-if="$route.params.profile === 'new'"
size="sm"
color="success"
class="mr-1"
@click="post"
>افزودن
</CButton>
<CButton v-else size="sm" color="success" class="mr-1" @click="update"
>بروزرسانی
</CButton
>
</CustomSubHeader>
<CRow>
<CCol>
<CCard>
<CCardBody>
<CRow>
<CCol lg="6">
<CForm>
<CRow v-if="$route.params.profile !== 'profile'">
<CCol sm="12">
<el-checkbox
v-model="user.registration_done"
label="کاربر فعال باشد"
/>
</CCol>
<el-divider></el-divider>
</CRow>
<template v-if="$route.params.profile !== 'new'">
<h4>مشخصات کاربر</h4>
<el-divider/>
</template>
<CRow>
<CCol sm="12">
<CInput
:class="validation.firstName ? 'err' : null"
label="نام"
:description="
validation.firstName ? validation.firstName.msg : null
"
v-model="user.firstName"
/>
</CCol>
<CCol sm="12">
<CInput
:class="validation.lastName ? 'err' : null"
label="نام خانوادگی"
:description="
validation.lastName ? validation.lastName.msg : null
"
v-model="user.lastName"
/>
</CCol>
<CCol sm="12">
<CInput
label="نام کاربری"
v-model="user.username"
:class="validation.username ? 'err' : null"
:description="
validation.username ? validation.username.msg : null
"
:disabled="$route.params.profile!=='new'"
/>
</CCol>
<CCol sm="12">
<CInput
label="تلفن همراه"
placeholder="اختیاری"
v-model="user.mobileNumber"
:class="validation.mobileNumber ? 'err' : null"
:description="
validation.mobileNumber
? validation.mobileNumber.msg
: null
"
/>
</CCol>
<CCol sm="12">
<CInput
:class="validation.email ? 'err' : null"
label="ایمیل"
v-model="user.email"
:description="
validation.email ? validation.email.msg : null
"
/>
</CCol>
<template v-if="$route.params.profile === 'new'">
<CCol sm="12">
<CInput
:class="validation.password ? 'err' : null"
label="کلمه عبور"
type="password"
:description="
validation.password ? validation.password.msg : null
"
v-model="user.password"
/>
</CCol>
<CCol sm="12">
<CInput
:class="
validation.password_confirmation ? 'err' : null
"
label="تکرار کلمه عبور"
type="password"
:description="
validation.password_confirmation
? validation.password_confirmation.msg
: null
"
v-model="user.password_confirmation"
/>
</CCol>
</template>
</CRow>
<el-divider/>
<template v-if="$route.params.profile !== 'profile'">
<h6>انتخاب محدوده دسترسی</h6>
<el-select
v-model="user.portals"
multiple
placeholder="انتخاب کنید"
style="width: 100%;"
@change="changePortalVal"
>
<el-option
v-for="item in portals"
:key="item.value"
:label="item.name"
:value="item.value"
>
</el-option>
</el-select>
<p
style="margin-top : 5px !important ; color : red"
class="form-err"
v-if="validation.portals"
>
{{ validation.portals.msg }}
</p>
<el-divider/>
<el-select
style="width: 100%;"
v-model="user.specialPermissions"
multiple
filterable
placeholder="انتخاب دسترسی خاص"
>
<el-option
v-for="item in filterSpecPer"
:key="item._id"
:label="item.title"
:value="item._id"
>
<!-- <span>{{setTitle(item)}}</span> -->
</el-option>
</el-select>
<p class="text-danger" v-if="!user.specialPermissions.length">درصورتی که دسته بندی خاصی را انتخاب
نکنید,کاربر به تمام اخبار دسترسی خواهد
داشت.</p>
<div style="margin-top : 5px">
<p
style="margin-top : 5px !important ; color : red"
class="form-err"
v-if="validation.specialPermissions"
>
{{ validation.specialPermissions.msg }}
</p>
</div>
<el-divider/>
<h6 class="mb-3">دسترسی های کاربر</h6>
<div class="user-permissions">
<p
style="margin-top : 5px !important ; color : red"
class="form-err"
v-if="validation.permissions"
>
{{ validation.permissions.msg }}
</p>
<el-tag
class="ml-2 mb-2"
style="cursor: pointer"
v-for="(item, index) in user.permissions"
:key="index + Math.random() + 1"
closable
disable-transitions
@close="removePermission(item)"
>
{{ getPermissionName(item) }}
</el-tag>
</div>
</template>
</CForm>
</CCol>
<CCol lg="6">
<CForm>
<CRow>
<CCol sm="12">
<h4>عکس پروفایل</h4>
<el-divider/>
<CCol>
<img
:src="user.profilePic"
style="width: 100%;max-width: 250px;"
alt=""
/>
</CCol>
<input
type="file"
ref="profilePic"
@change="imagePreview"
/>
<p
style="margin-top : 5px !important ;"
class="form-err"
v-if="validation.profilePic"
>
{{ validation.profilePic.msg }}
</p>
<p class="mt-3 text-muted">
عکس 500*500 باشد. در غیر این صورت اتوماتیک بریده می شود.
</p>
<CCol></CCol>
<p
style="margin-top : 0px !important ; "
class="form-err"
v-if="validation.password_confirmation"
>
{{ validation.password_confirmation.msg }}
</p>
</CCol>
<template v-if="$route.params.profile !== 'new'">
<CCol sm="12" class="mt-5">
<h4>تغییر کلمه عبور</h4>
<el-divider/>
<CInput
:class="validation.password ? 'err' : null"
label="کلمه عبور"
type="password"
:description="
validation.password ? validation.password.msg : null
"
v-model="newPass.password"
/>
</CCol>
<CCol sm="12">
<CInput
:class="
validation.password_confirmation ? 'err' : null
"
label="تکرار کلمه عبور"
type="password"
:description="
validation.password_confirmation
? validation.password_confirmation.msg
: null
"
v-model="newPass.password_confirmation"
/>
<CButton
size="sm"
color="success"
class="mr-1 mt-3"
@click="updatePassword"
>تغییر کلمه عبور
</CButton>
</CCol>
</template>
</CRow>
</CForm>
</CCol>
</CRow>
</CCardBody>
</CCard>
<CCard v-if="$route.params.profile !== 'profile'">
<CCardBody>
<h6 class="mb-3" style="color:#000">لیست کل دسترسی ها</h6>
<div class="permissions">
<el-tag
class="ml-2 mb-2"
style="cursor: pointer"
v-for="(item, index) in permissions"
:key="index + Math.random() + 2"
:type="hasPermission(item.value) ? 'success' : 'primary'"
disable-transitions
@click="addPermission(item.value)"
>{{ item.name }}
</el-tag>
</div>
</CCardBody>
</CCard>
</CCol>
</CRow>
</div>
</template>
<script>
import axiosUploadProcess from "@/mixins/axiosUploadProcess"
export default {
data() {
return {
user: null,
permissions: null,
specialPermissions: null,
newPass: {
password: '',
password_confirmation: ''
},
validation: {},
portals: null,
filterSpecPer: null
}
},
mixins: [axiosUploadProcess],
computed: {
title() {
return this.$route.params.profile === 'new' ? 'افزودن کاربر' : 'مشاهده پروفایل کاربر'
}
},
methods: {
changePortalVal(value) {
this.user.specialPermissions = [];
this.filterSpecPer = this.specialPermissions.filter(item => value.includes(item.modelType));
},
getPermissionName(value) {
if (value) {
return this.permissions.filter(item => item.value === value)[0].name
}
},
addPermission(val) {
if (!this.user.permissions.includes(val) && !this.user.permissions.includes('superAdmin')) {
val === 'superAdmin' ? this.user.permissions = [val] : this.user.permissions.push(val)
} else {
this.$message({
type: 'warning',
message: 'کاربر از قبل این دسترسی را دارد'
});
}
},
removePermission(val) {
this.user.permissions = this.user.permissions.filter(item => item !== val)
},
hasPermission(val) {
if (this.user.permissions.includes('superAdmin')) {
return true;
} else {
return this.user.permissions.includes(val)
}
},
imagePreview(e) {
this.user.profilePic = URL.createObjectURL(e.target.files[0])
},
post() {
this.validation = {}
const data = new FormData()
data.append("firstName", this.user.firstName.trim())
data.append("lastName", this.user.lastName.trim())
data.append("mobileNumber", this.user.mobileNumber.trim())
data.append("email", this.user.email.trim())
data.append("username", this.user.username.trim())
data.append("permissions", JSON.stringify(this.user.permissions))
data.append("password", this.user.password)
data.append("portals", JSON.stringify(this.user.portals))
data.append("specialPermissions", JSON.stringify(this.user.specialPermissions))
data.append("registration_done", !this.user?.registration_done ? false : this.user.registration_done)
data.append("password_confirmation", this.user.password_confirmation)
if (this.$refs.profilePic.files[0]) data.append("profilePic", this.$refs.profilePic.files[0])
this.$axios.post(`/api/admin/user/registerAdmin`, data, this.axiosConfig)
.then(response => {
this.$message({
type: 'success',
message: 'کاربر با موفقیت ایجاد شد.'
})
this.$router.push({
name: 'admin-users'
})
})
.catch(err => {
if (err.response.status === 401) {
return this.$message({
type: 'error',
message: 'لطفا دوباره وارد سیستم شوید.'
})
}
if (err.response.status === 422) this.validation = err.response.data.validation
else console.log(err.response.data)
})
},
update() {
this.validation = {};
const data = new FormData();
data.append("firstName", this.user.firstName.trim())
data.append("lastName", this.user.lastName.trim())
data.append("mobileNumber", this.user.mobileNumber.trim())
data.append("email", this.user.email.trim())
data.append("username", this.user.username.trim())
data.append("permissions", JSON.stringify(this.user.permissions))
data.append("password", this.user.password)
data.append("portals", JSON.stringify(this.user.portals))
data.append("specialPermissions", JSON.stringify(this.user.specialPermissions))
data.append("registration_done", !this.user?.registration_done ? false : this.user.registration_done)
data.append("password_confirmation", this.user.password_confirmation)
if (this.$refs.profilePic.files[0]) data.append("profilePic", this.$refs.profilePic.files[0])
this.$axios.put(this.$route.params.profile === 'profile' ? '/api/admin/profile' : `/api/admin/user/${this.user._id}`, data, this.axiosConfig)
.then(response => {
this.$message({
type: 'success',
message: 'اطلاعات بروزرسانی شد.'
})
this.$nuxt.refresh()
})
.catch(err => {
if (err.response.status === 401) {
return this.$message({
type: 'error',
message: 'لطفا دوباره وارد سیستم شوید.'
})
}
if (err.response.status === 422) this.validation = err.response.data.validation
else console.log(err.response.data);
})
},
updatePassword() {
this.validation = {}
this.$axios.put(this.$route.params.profile === 'profile' ? '/api/admin/profile/changePass' : `/api/admin/user/changePass/${this.user._id}`, this.newPass)
.then(async (response) => {
this.$message({
type: 'success',
message: 'کلمه عبور بروزرسانی شد.'
})
this.newPass = {
password: '',
password_confirmation: ''
}
if (this.$route.params.profile === 'profile') {
await this.$auth.logout()
window.location.replace('/admin/login');
}
})
.catch(err => {
if (err.response.status === 401) {
return this.$message({
type: 'error',
message: 'لطفا دوباره وارد سیستم شوید.'
})
}
if (err.response.status === 422) this.validation = err.response.data.validation
else console.log(err.response.data)
})
}
},
head() {
return {
title: this.title
}
},
layout: 'admin',
async asyncData({
$axios,
params,
error
}) {
try {
// const permissions = await $axios.get('/api/admin/permissions',{ progress: false });
// const portals = await $axios.get('/api/admin/portals',{ progress: false });
// const specialPermissions = await $axios.get('/api/admin/category/permissions',{ progress: false });
const requests = [
$axios.get('/api/admin/permissions', {progress: false}),
$axios.get('/api/admin/portals', {progress: false}),
$axios.get('/api/admin/category/permissions', {progress: false})
];
const fetch = await Promise.all(requests);
let [permissions, portals, specialPermissions] = fetch;
if (params.profile === 'profile') {
const user = await $axios.get(`/api/admin/profile`);
return {
portals: portals.data,
permissions: permissions.data,
specialPermissions: specialPermissions.data,
filterSpecPer: specialPermissions.data.filter(item => user.data.portals.includes(item.modelType)),
user: user.data
}
} else if (params.profile !== 'new') {
var user = await $axios.get(`/api/admin/user/${params.profile}`);
var permissionsArr = [];
for (const item of user.data.specialPermissions) {
permissionsArr.push(item._id);
}
user.data.specialPermissions = permissionsArr;
return {
portals: portals.data,
permissions: permissions.data,
specialPermissions: specialPermissions.data,
filterSpecPer: specialPermissions.data.filter(item => user.data.portals.includes(item.modelType)),
user: user.data
}
} else {
return {
portals: portals.data,
permissions: permissions.data,
specialPermissions: specialPermissions.data,
user: {
firstName: '',
lastName: '',
mobileNumber: '',
email: '',
username: '',
password: '',
portals: [],
password_confirmation: '',
profilePic: '',
permissions: [],
specialPermissions: []
}
}
}
} catch (e) {
if (e?.response?.status === 401) {
error({
status: 401,
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (e?.response?.status === 403) {
error({
status: 403,
message: e?.response?.data?.message,
});
}
if (e?.response?.status === 500) {
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات پیش آمده",
});
} else
error({
status: 404,
message: "اطلاعات کاربر مورد نظر پیدا نشد",
});
}
}
}
</script>
+307
View File
@@ -0,0 +1,307 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="success" :to="{name: 'admin-users-profile',params:{profile: 'new'}}" class="mr-auto">
افزودن
</CButton>
</CustomSubHeader>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-filter"></i>
<span style="color:#000">فیلتر</span>
</slot>
</CCardHeader>
<CCardBody>
<CRow>
<CCol md="6">
<CRow style="flex-direction : column;">
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>نام و نام خانوادگی</span>
</CCol>
<CCol col="md-9">
<el-input style="width : 100%" placeholder="" v-model="search.name"></el-input>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>ایمیل</span>
</CCol>
<CCol col="md-9">
<el-input style="width : 100%" placeholder="" v-model="search.email"></el-input>
</CCol>
</CRow>
</CCol>
</CRow>
</CCol>
<CCol md="6">
<CRow style="flex-direction : column;">
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>محدوده دسترسی</span>
</CCol>
<CCol col="md-9">
<el-select v-model="search.portals" clearable style="width : 100%">
<el-option v-for="item in portals" :key="item.value" :label="item.name" :value="item.value">
</el-option>
</el-select>
</CCol>
</CRow>
</CCol>
<CCol class="mt-3">
<CRow style="align-items: baseline;">
<CCol col="md-3" class="mb-2">
<span>وضعیت کاربر</span>
</CCol>
<CCol col="md-9">
<el-select v-model="search.status" clearable style="width : 100%">
<el-option :key="true" label="فعال" :value="true">
</el-option>
<el-option :key="false" label="غیر فعال" :value="false">
</el-option>
</el-select>
</CCol>
</CRow>
</CCol>
</CRow>
</CCol>
</CRow>
<CRow>
<el-button :loading="loading" @click="handelSearch" size="small" style="width: auto;margin: 25px auto auto auto;" type="primary" icon="el-icon-search">
جست و جو
</el-button>
</CRow>
</CCardBody>
</CCard>
<CCard>
<CCardHeader>
<slot name="header">
<i class="fal fa-bars"></i>
<span>{{ list_title }}</span>
</slot>
<slot>
</slot>
</CCardHeader>
<CCardBody>
<el-table v-loading="loading" :data="users.docs" style="width: 100%">
<el-table-column type="index" label="#">
</el-table-column>
<el-table-column label="عکس پروفایل" width="170">
<template slot-scope="scope">
<img :src="scope.row.profilePic || '/img/avatar.png'" style="width: 50px; border-radius: 50em;"
:alt="scope.row.firstName + ' ' + scope.row.lastName">
</template>
</el-table-column>
<el-table-column label="نام و نام خانوادگی">
<template slot-scope="scope">
<span>{{ scope.row.firstName + ' ' + scope.row.lastName }}</span>
</template>
</el-table-column>
<el-table-column prop="username" label="نام کاربری" width="">
</el-table-column>
<el-table-column label="وضعیت کاربر" width="">
<template slot-scope="scope">
<el-tag :type="scope.row.registration_done?'primary' : 'danger'">
{{ scope.row.registration_done ? 'فعال' : 'غیر فعال' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="ویرایش" width="110" align="center">
<template slot-scope="scope">
<CButton :color="scope.row.registration_done ? 'danger' : 'success'" :title="scope.row.registration_done ? 'غیرفعال کردن کاربر' : 'فعال کردن کاربر'" variant="outline"
:key="scope.row._id + Math.random()"
@click="changeUserStatus(scope.row)">
<i class="fas fa-power-off"></i>
</CButton>
<CButton color="success" variant="outline" :key="scope.row._id"
:to="{name: 'admin-users-profile',params: {profile: scope.row._id}}">
<i class="far fa-eye"></i>
</CButton>
</template>
</el-table-column>
</el-table>
</CCardBody>
</CCard>
<CCard class="col" v-if="users.totalDocs>5">
<CRow alignHorizontal="center" style="padding : 10px">
<el-pagination :hide-on-single-page="true" layout="prev, pager, next" :page-size="users.limit"
@current-change="handleCurrentChange" :current-page.sync="users.page" :total="users.totalDocs">
</el-pagination>
</CRow>
</CCard>
</div>
</template>
<script>
const _ = require('lodash');
export default {
data() {
return {
title: 'لیست کاربران',
list_title: 'لیست',
users: null,
search: {},
portals: [],
loading: false
}
},
computed: {
pageQuery() {
return this.$route.query.page;
}
},
watch: {
pageQuery(newPage, oldPage) {
this.$nuxt.refresh();
}
},
methods: {
handleCurrentChange(page) {
if (!_.isEmpty(this.search)) {
this.handelSearch(page);
} else {
this.$router.push({
name: "admin-users",
query: {
page: page
}
});
}
},
handelSearch(page) {
this.loading = true;
const data = {
name: this.search.name,
email: this.search.email,
status: this.search.status,
portals: this.search.portals
}
this.$axios.post(`/api/admin/user/search?page=${page}`, data, this.axiosConfig)
.then((result) => {
this.users = result.data;
this.loading = false;
})
.catch(err => {
this.loading = false;
if (err.response.status === 401) {
return this.$message({
type: 'error',
message: 'لطفا دوباره وارد سیستم شوید.'
})
}
if (err.response.status === 422) this.validation = err.response.data.validation
else console.log(err.response.data)
})
},
changeUserStatus(user) {
this.$confirm(user.registration_done ? 'کاربر غیرفعال شود؟' : 'کاربر فعال شود؟', 'هشدار', {
confirmButtonText: 'بله',
cancelButtonText: 'لغو',
type: user.registration_done ? 'error' : 'warning'
}).then(async () => {
this.$axios.put(`/api/admin/user/changeStatus/${user._id}`)
.then(res => {
this.$message({
type: 'success',
message: 'وضعیت حساب کاربر با موفقیت تغییر کرد'
})
this.$nuxt.refresh()
})
.catch(err => {
if (err.response.status === 401) {
return this.$message({
type: 'error',
message: 'لطفا دوباره وارد سیستم شوید.'
})
}
if (err.response.status === 403) {
return this.$message({
type: 'error',
message: err.response.data.message
})
}
if (err.response.status === 422) {
return this.$message({
type: 'error',
message: err.response.data.message
})
}
console.log(err.response.data)
})
}).catch(() => {
this.$message({
type: 'warning',
message: 'عملیات لغو شد'
})
})
}
},
head() {
return {
title: this.title
}
},
layout: 'admin',
async asyncData({
$axios,
query,
redirect,
error
}) {
try {
// const users = await $axios.get(`/api/admin/user?page=${query.page}` , { progress: false })
// const portals = await $axios.get('/api/admin/portals' , { progress: false });
const requests = [
$axios.get(`/api/admin/user?page=${query.page}`, {progress: false}),
$axios.get('/api/admin/portals', {progress: false})
];
const fetch = await Promise.all(requests);
let [users, portals] = fetch;
if (query.page > 1 && users.data.totalPages < query.page) {
redirect('/admin/users');
} else {
return {
users: users.data,
portals: portals.data
}
}
} catch (e) {
if (e?.response?.status === 401) {
error({
status: 401,
message: 'شما اجازه دسترسی به این صفحه را ندارید'
})
} else {
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات بوجود آمده است",
});
}
}
}
}
</script>
+113
View File
@@ -0,0 +1,113 @@
<template>
<div>
<CustomSubHeader>
<CBreadcrumb class="border-0 mb-0">{{ title }}</CBreadcrumb>
<CButton size="sm" color="success" class="mr-auto" @click="update">بروزرسانی</CButton>
</CustomSubHeader>
<CCard>
<CCardBody>
<CRow>
<CCol>
<img :src="yearBanner.mainCover" alt="" style="width: 100%;">
<p v-if="validation.mainCover">{{ validation.mainCover.msg }}</p>
<input type="file" ref="file" @change="imagePreview">
<el-divider></el-divider>
<el-checkbox label="نمایش پرچم ایران" v-model="yearBanner.iranFlag"/>
</CCol>
</CRow>
</CCardBody>
</CCard>
</div>
</template>
<script>
import axiosUploadProcess from "@/mixins/axiosUploadProcess"
export default {
data() {
return {
title: 'تغییر تصویر شعار سال در هدر',
yearBanner: null,
validation: {}
}
},
mixins: [axiosUploadProcess],
methods: {
imagePreview(e) {
this.yearBanner.mainCover = URL.createObjectURL(e.target.files[0]);
},
update() {
this.validation = {}
const data = new FormData()
data.append('mainCover', this.$refs.file.files[0])
data.append('iranFlag', this.yearBanner.iranFlag)
data.append('electionBtn', this.yearBanner.electionBtn)
// socialLinks
data.append('hasEmail', this.yearBanner.hasEmail)
data.append('hasGPlus', this.yearBanner.hasGPlus)
data.append('hasTweeter', this.yearBanner.hasTweeter)
data.append('hasInstagram', this.yearBanner.hasInstagram)
data.append('email', this.yearBanner.email)
data.append('gPlus', this.yearBanner.gPlus)
data.append('tweeter', this.yearBanner.tweeter)
data.append('instagram', this.yearBanner.instagram)
this.$axios.post('/api/admin/yearBanner', data, this.axiosConfig)
.then(res => {
this.$message({
type: 'success',
message: 'تغییرات با موفقیت انجام شد'
})
this.$refs.file.value = null
this.$nuxt.refresh()
})
.catch(err => {
if (err.response?.status === 422) {
this.validations = err.response.data.validation
this.$message({
type: 'warning',
message: 'پارامترها را بررسی کنید'
})
} else console.log(e)
})
}
},
head() {
return {
title: this.title,
};
},
layout: "admin",
async asyncData({$axios, error}) {
try {
const yearBanner = await $axios.get('/api/public/yearBanner')
return {
yearBanner: yearBanner.data
}
} catch (e) {
if (e?.response?.status === 401) {
error({
status: 401,
message: "لطفا دوباره وارد سیستم شوید.",
});
}
if (e?.response?.status === 403) {
error({
status: 403,
message: e?.response?.data?.message,
});
}
if (e?.response?.status === 500) {
error({
status: 500,
message: "مشکلی در گرفتن اطلاعات پیش آمده",
});
} else
error({
status: 404,
message: "اسلایدر مورد نظر پیدا نشد",
});
}
},
}
</script>