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
+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>