|
@@ -0,0 +1,303 @@
|
|
|
+<template>
|
|
|
+ <div class="contentBox">
|
|
|
+ <el-card class="box-card-left">
|
|
|
+ <div slot="header">
|
|
|
+ <span>菜单列表</span>
|
|
|
+ </div>
|
|
|
+ <deepTree @nodeClick="treeClick" class="deepTree" :data="treeList"></deepTree>
|
|
|
+ </el-card>
|
|
|
+ <el-card class="box-card">
|
|
|
+ <div slot="header" class="clearfix">
|
|
|
+ <span>文章管理</span>
|
|
|
+ <el-button style="float: right; padding: 3px 0" type="text" @click="addcontents" icon="el-icon-plus">添加文章</el-button>
|
|
|
+ </div>
|
|
|
+ <div class="main">
|
|
|
+ <filterList ref="filterList" :operation="operation" :tableData="contents" :filed="filed" @edit="filtereEdit" @delete="filterDelete" @query="filterQuery" :total="Total">
|
|
|
+ <template v-slot:search="{ item, formInline }">
|
|
|
+ <el-select v-model="formInline[item.name]" placeholder="请选择菜单" v-if="item.name == 'bind'">
|
|
|
+ <el-option v-for="item in menus" :key="item.code" :label="item.name" :value="item.code"></el-option>
|
|
|
+ </el-select>
|
|
|
+ </template>
|
|
|
+ </filterList>
|
|
|
+ </div>
|
|
|
+ </el-card>
|
|
|
+ <dialogAndDrawer :width="'35%'" :title="title" :visibleSync="visibleSync" v-if="visibleSync" @close="visibleSync = false, lookUser = false">
|
|
|
+ <template v-slot:windowMain>
|
|
|
+ <formData v-if="!lookUser" ref="formData" :filed="formfiled" :data="formdata" :rules="formrules" @save="formSave">
|
|
|
+ <template v-slot:formItem="{ item, formdata }">
|
|
|
+ <el-switch v-if="item.name == 'istop'" v-model="formdata[item.name]" active-color="#13ce66" inactive-color="#ff4949" :active-value="true" :inactive-value="false"></el-switch>
|
|
|
+ <!-- 缩略图 -->
|
|
|
+ <el-upload
|
|
|
+ v-if="item.name == 'thumbnail'"
|
|
|
+ class="avatar-uploader"
|
|
|
+ action="/api/files/avatar/upload"
|
|
|
+ :show-file-list="false"
|
|
|
+ :headers="myHeaders"
|
|
|
+ :on-success="handleAvatarSuccess"
|
|
|
+ :before-upload="beforeAvatarUpload">
|
|
|
+ <img v-if="formdata[item.name] && formdata[item.name] !== ''" :src="formdata[item.name]" class="avatar">
|
|
|
+ <i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
|
|
+ </el-upload>
|
|
|
+ <!-- 富文本 -->
|
|
|
+ <editoritem v-if="item.name == 'content'" @change="editChage" :value="formdata[item.name]"></editoritem>
|
|
|
+ <!-- 附件上传 -->
|
|
|
+ <el-upload
|
|
|
+ v-if="item.name == 'annex'"
|
|
|
+ :headers="myHeaders"
|
|
|
+ class="upload-demo"
|
|
|
+ action="/api/files/avatar/upload"
|
|
|
+ :on-success="handleAnnexSuccess"
|
|
|
+ :on-remove="handleRemove"
|
|
|
+ :file-list="fileList">
|
|
|
+ <el-button size="small" type="primary">附件上传</el-button>
|
|
|
+ </el-upload>
|
|
|
+ </template>
|
|
|
+ </formData>
|
|
|
+ <filterList v-else ref="filterList" :tableData="userList" :filter="false" :readOnly="true" :filed="userfiled" @query="userfilterQuery" :total="userTotal"></filterList>
|
|
|
+ </template>
|
|
|
+ </dialogAndDrawer>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+<script>
|
|
|
+import filterList from '@components/filterList/index.vue';
|
|
|
+import dialogAndDrawer from '@components/dialogAndDrawer.vue';
|
|
|
+import formData from '@components/formData/index.vue';
|
|
|
+import editoritem from '@components/editoritem.vue';
|
|
|
+import deepTree from '@components/deepTree.vue';
|
|
|
+import { mapState, mapActions } from 'vuex';
|
|
|
+const token = sessionStorage.getItem('token');
|
|
|
+export default {
|
|
|
+ components: {
|
|
|
+ filterList,
|
|
|
+ dialogAndDrawer,
|
|
|
+ formData,
|
|
|
+ editoritem,
|
|
|
+ deepTree
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ types: null,
|
|
|
+ info: {},
|
|
|
+ lookUser: false,
|
|
|
+ fileList: [],
|
|
|
+ myHeaders: { Authorization: token },
|
|
|
+ title: '',
|
|
|
+ visibleSync: false,
|
|
|
+ filed: [
|
|
|
+ { name: 'title', label: '标题', filter: true },
|
|
|
+ // { name: 'bind', label: '绑定栏目', formater: 'slot', filter: true },
|
|
|
+ { name: 'visit', label: '访问量' }
|
|
|
+ ],
|
|
|
+ formdata: {},
|
|
|
+ userfiled: [
|
|
|
+ { name: 'name', label: '名称' },
|
|
|
+ { name: 'phone', label: '手机号' }
|
|
|
+ ],
|
|
|
+ formfiled: [
|
|
|
+ { name: 'thumbnail', label: '缩略图', formater: 'slot' },
|
|
|
+ { name: 'title', label: '标题' },
|
|
|
+ { name: 'describe', label: '描述' },
|
|
|
+ { name: 'bind', label: '绑定菜单', formater: 'dict:menus' },
|
|
|
+ { name: 'date', label: '时间', formater: 'date:datetime' },
|
|
|
+ { name: 'istop', label: '置顶', formater: 'slot' },
|
|
|
+ { name: 'content', label: '内容', formater: 'slot' },
|
|
|
+ { name: 'annex', label: '附件', formater: 'slot' }
|
|
|
+ ],
|
|
|
+ formrules: {
|
|
|
+ thumbnail: [
|
|
|
+ { required: true, message: '请上传缩略图', trigger: 'chage' }
|
|
|
+ ],
|
|
|
+ title: [
|
|
|
+ { required: true, message: '请输入标题', trigger: 'blur' }
|
|
|
+ ],
|
|
|
+ describe: [
|
|
|
+ { required: true, message: '请输入描述', trigger: 'blur' }
|
|
|
+ ],
|
|
|
+ bind: [
|
|
|
+ { required: true, message: '请绑定菜单', trigger: 'chage' }
|
|
|
+ ],
|
|
|
+ date: [
|
|
|
+ { required: true, message: '请输入时间', trigger: 'blur' }
|
|
|
+ ],
|
|
|
+ content: [
|
|
|
+ { required: true, message: '请输入内容', trigger: 'blur' }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ operation: [
|
|
|
+ { name: 'edit', label: '修改', icon: 'el-icon-edit' },
|
|
|
+ { name: 'delete', label: '删除', icon: 'el-icon-delete' }
|
|
|
+ ]
|
|
|
+ };
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ ...mapState(['contentsList', 'Total', 'menusList', 'userList', 'userTotal', 'dict']),
|
|
|
+ contents() {
|
|
|
+ this.contentsList.map(p => {
|
|
|
+ const findName = this.menusList.find(e => e.code == p.bind);
|
|
|
+ console.log(findName);
|
|
|
+ if (findName) p.bind = findName?.name;
|
|
|
+ return p;
|
|
|
+ });
|
|
|
+ return this.contentsList;
|
|
|
+ },
|
|
|
+ menus() {
|
|
|
+ const menus = this.menusList.filter(e => e.parentCode !== 'null' && e.type == 1);
|
|
|
+ return menus;
|
|
|
+ },
|
|
|
+ treeList() {
|
|
|
+ const menusall = this.menusList.filter(e => (e.type !== 2 && e.type !== '2'));
|
|
|
+ return this.$tree(menusall);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async created() {
|
|
|
+ await this.filterQuery();
|
|
|
+ await this.menusQuery();
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ ...mapActions(['contentsQuery', 'contentsCreate', 'contentsUpdate', 'contentsDelete', 'contentsQuery', 'contentsFetch', 'menusQuery', 'userQuery']),
|
|
|
+ // 添加
|
|
|
+ addcontents () {
|
|
|
+ this.formdata = {};
|
|
|
+ this.title = '添加文章';
|
|
|
+ this.visibleSync = true;
|
|
|
+ if (this.types !== null) this.$set(this.formdata, 'bind', this.types);
|
|
|
+ },
|
|
|
+ // 修改
|
|
|
+ async filtereEdit (e) {
|
|
|
+ const res = await this.contentsFetch({ id: e._id });
|
|
|
+ this.formdata = res.data;
|
|
|
+ this.title = '修改文章';
|
|
|
+ this.visibleSync = true;
|
|
|
+ },
|
|
|
+ // 删除
|
|
|
+ async filterDelete (e) {
|
|
|
+ const res = await this.contentsDelete({ id: e?._id });
|
|
|
+ this.$resChange(res, '删除成功');
|
|
|
+ this.filterQuery();
|
|
|
+ },
|
|
|
+ // 查询
|
|
|
+ async filterQuery ({ filter = {}, paging = { page: 0, size: 10 } } = {}) {
|
|
|
+ // filter.istop = true;
|
|
|
+ await this.contentsQuery({ filter, paging });
|
|
|
+ },
|
|
|
+ // 表单保存
|
|
|
+ async formSave (e) {
|
|
|
+ if (e.isRevise && e?.isRevise == false) {
|
|
|
+ this.$message.warning('未作修改');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.$delete(e, 'isRevise');
|
|
|
+ let res, msg;
|
|
|
+ // 修改
|
|
|
+ if (e._id) {
|
|
|
+ delete e.svip;
|
|
|
+ delete e.isShow;
|
|
|
+ res = await this.contentsUpdate(e);
|
|
|
+ msg = '文章修改成功';
|
|
|
+ } else {
|
|
|
+ res = await this.contentsCreate(e);
|
|
|
+ msg = '文章修改成功';
|
|
|
+ }
|
|
|
+ this.$resChange(res, msg);
|
|
|
+ const filter = { bind: this.types };
|
|
|
+ this.filterQuery({ filter });
|
|
|
+ this.visibleSync = false;
|
|
|
+ },
|
|
|
+ // 富文本改变
|
|
|
+ editChage (e) {
|
|
|
+ this.$refs.formData.setForm('content', e);
|
|
|
+ },
|
|
|
+ // 附件上传
|
|
|
+ handleAnnexSuccess(res, file) {
|
|
|
+ this.$refs.formData.setForm('annex', res.data.filePath);
|
|
|
+ this.fileList.push({ name: res.data.name, url: res.data.filePath });
|
|
|
+ },
|
|
|
+ // 删除附件列表
|
|
|
+ handleRemove(file, fileList) {
|
|
|
+ console.log(123);
|
|
|
+ this.$refs.formData.setForm('annex', null);
|
|
|
+ delete this.fileList[0];
|
|
|
+ },
|
|
|
+ // 缩略图上传
|
|
|
+ handleAvatarSuccess(res, file) {
|
|
|
+ this.$refs.formData.setForm('thumbnail', res.data.filePath);
|
|
|
+ },
|
|
|
+ // 缩略图上传限制
|
|
|
+ beforeAvatarUpload(file) {
|
|
|
+ const isJPG = file.type === 'image/jpeg';
|
|
|
+ const isLt2M = file.size / 1024 / 1024 < 2;
|
|
|
+
|
|
|
+ if (!isJPG) {
|
|
|
+ this.$message.error('上传头像图片只能是 JPG 格式!');
|
|
|
+ }
|
|
|
+ if (!isLt2M) {
|
|
|
+ this.$message.error('上传头像图片大小不能超过 2MB!');
|
|
|
+ }
|
|
|
+ return isJPG && isLt2M;
|
|
|
+ },
|
|
|
+ async treeClick({ data, node }) {
|
|
|
+ if (data.children) return;
|
|
|
+ this.types = data.code;
|
|
|
+ const filter = { bind: data.code };
|
|
|
+ await this.filterQuery({ filter });
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+</script>
|
|
|
+<style lang="scss" scoped>
|
|
|
+.contentBox {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ .box-card {
|
|
|
+ width: 80%;
|
|
|
+ height: 100%;
|
|
|
+ .el-card__body {
|
|
|
+ height: 100%;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .box-card-left {
|
|
|
+ width: 20%;
|
|
|
+ height: 100%;
|
|
|
+ ::v-deep .el-card__body {
|
|
|
+ height: 88%;
|
|
|
+ .deepTree {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ overflow-y: auto;
|
|
|
+ }
|
|
|
+ .deepTree::-webkit-scrollbar {
|
|
|
+ width: 0px;
|
|
|
+ height: 0px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+.el-dialog {
|
|
|
+ .avatar-uploader-icon {
|
|
|
+ font-size: 28px;
|
|
|
+ color: #8c939d;
|
|
|
+ width: 120px;
|
|
|
+ height: 120px;
|
|
|
+ line-height: 120px;
|
|
|
+ text-align: center;
|
|
|
+ }
|
|
|
+ .avatar {
|
|
|
+ width: 120px;
|
|
|
+ height: 120px;
|
|
|
+ display: block;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|
|
|
+<style>
|
|
|
+.el-upload {
|
|
|
+ border: 1px dashed #d9d9d9;
|
|
|
+ border-radius: 6px;
|
|
|
+ cursor: pointer;
|
|
|
+ position: relative;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+.el-upload:hover {
|
|
|
+ border-color: #409EFF;
|
|
|
+}
|
|
|
+</style>
|