|
@@ -1,41 +1,52 @@
|
|
<template>
|
|
<template>
|
|
<div id="index">
|
|
<div id="index">
|
|
<detail-frame :title="pageTitle">
|
|
<detail-frame :title="pageTitle">
|
|
- <el-row :gutter="10" type="flex">
|
|
|
|
- <el-col :span="12">
|
|
|
|
|
|
+ <el-row :gutter="10" type="flex" justify="end" class="btn_bar">
|
|
|
|
+ <el-col :span="4">
|
|
<el-row>
|
|
<el-row>
|
|
- <el-col :span="6"><el-button type="text" @click="toDialog()">添加主菜单</el-button></el-col>
|
|
|
|
|
|
+ <el-col :span="6"><el-button type="primary" size="small" @click="toDialog()">添加主目录</el-button></el-col>
|
|
</el-row>
|
|
</el-row>
|
|
- <el-tree :data="list" ref="tree" node-key="id" :props="defaultProps" :highlight-current="true">
|
|
|
|
- <span class="custom-tree-node" slot-scope="{ node, data }">
|
|
|
|
- <span>
|
|
|
|
- <el-button type="text" @click="toUpdate(node, data)" style="font-size:16px">
|
|
|
|
- {{ node.label }}
|
|
|
|
- </el-button>
|
|
|
|
- </span>
|
|
|
|
- <span>
|
|
|
|
- <el-button type="text" @click="toAppend(node, data)">
|
|
|
|
- 添加子菜单
|
|
|
|
- </el-button>
|
|
|
|
- <el-button type="text" @click="toRemove(node, data)">
|
|
|
|
- 删除菜单
|
|
|
|
- </el-button>
|
|
|
|
- </span>
|
|
|
|
- </span>
|
|
|
|
- </el-tree>
|
|
|
|
</el-col>
|
|
</el-col>
|
|
</el-row>
|
|
</el-row>
|
|
|
|
+ <el-table :data="list" row-key="title" border stripe :tree-props="defaultProps" :default-expand-all="true">
|
|
|
|
+ <el-table-column header-align="center" label="目录名称" prop="title"></el-table-column>
|
|
|
|
+ <el-table-column align="center" label="目录路由" prop="route"></el-table-column>
|
|
|
|
+ <el-table-column align="center" label="操作">
|
|
|
|
+ <template v-slot="{ row }">
|
|
|
|
+ <el-row :gutter="10" type="flex">
|
|
|
|
+ <el-col :span="8">
|
|
|
|
+ <el-link align="center" size="mini" type="primary" @click="toDialog(row)">修改目录</el-link>
|
|
|
|
+ </el-col>
|
|
|
|
+ <el-col :span="8">
|
|
|
|
+ <el-link align="center" size="mini" type="success" @click="toDialog(row, 'append')">添加子目录</el-link>
|
|
|
|
+ </el-col>
|
|
|
|
+ <el-col :span="8">
|
|
|
|
+ <el-link align="center" size="mini" type="danger" @click="toRemove(row)">删除目录</el-link>
|
|
|
|
+ </el-col>
|
|
|
|
+ </el-row>
|
|
|
|
+ </template>
|
|
|
|
+ </el-table-column>
|
|
|
|
+ </el-table>
|
|
</detail-frame>
|
|
</detail-frame>
|
|
- <el-dialog title="添加菜单" width="30%" center :visible.sync="dialog" @close="toClose" :destroy-on-close="true">
|
|
|
|
- <el-form :model="form" label-width="100px">
|
|
|
|
- <el-form-item label="上级菜单">
|
|
|
|
- {{ getNodeTitle(form) }}
|
|
|
|
|
|
+ <el-dialog title="添加目录" width="30%" center :visible.sync="dialog" @close="toClose" :destroy-on-close="true">
|
|
|
|
+ <el-form :model="form" label-width="100px" :rules="rules">
|
|
|
|
+ <el-form-item label="所属目录">
|
|
|
|
+ {{ form.pname || '主目录' }}
|
|
</el-form-item>
|
|
</el-form-item>
|
|
- <el-form-item label="菜单名称" prop="title" required>
|
|
|
|
- <el-input v-model="form.title" placeholder="请输入菜单名称"></el-input>
|
|
|
|
|
|
+ <el-form-item label="目录名称" prop="title" required>
|
|
|
|
+ <el-input v-model="form.title" placeholder="请输入目录称"></el-input>
|
|
</el-form-item>
|
|
</el-form-item>
|
|
- <el-form-item label="菜单路由">
|
|
|
|
- <el-input v-model="form.route" placeholder="请输入菜单路由(有子菜单可以为空)"></el-input>
|
|
|
|
|
|
+ <el-form-item label="目录路由">
|
|
|
|
+ <el-input v-model="form.route" placeholder="请输入目录路由(有子目录可以为空)"></el-input>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ <el-form-item label="目录优先级(降序排列)">
|
|
|
|
+ <el-input-number v-model="form.sort"></el-input-number>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ <el-form-item label="是否使用">
|
|
|
|
+ <el-radio-group v-model="form.disabled">
|
|
|
|
+ <el-radio :label="false">启用</el-radio>
|
|
|
|
+ <el-radio :label="true">禁用</el-radio>
|
|
|
|
+ </el-radio-group>
|
|
</el-form-item>
|
|
</el-form-item>
|
|
<el-form-item>
|
|
<el-form-item>
|
|
<el-button type="primary" @click="append">保存</el-button>
|
|
<el-button type="primary" @click="append">保存</el-button>
|
|
@@ -50,6 +61,7 @@ const _ = require('lodash');
|
|
import detailFrame from '@frame/layout/admin/detail-frame';
|
|
import detailFrame from '@frame/layout/admin/detail-frame';
|
|
import dataForm from '@frame/components/form';
|
|
import dataForm from '@frame/components/form';
|
|
import { mapState, createNamespacedHelpers } from 'vuex';
|
|
import { mapState, createNamespacedHelpers } from 'vuex';
|
|
|
|
+const { mapActions: menu } = createNamespacedHelpers('menu');
|
|
export default {
|
|
export default {
|
|
name: 'index',
|
|
name: 'index',
|
|
props: {},
|
|
props: {},
|
|
@@ -57,66 +69,77 @@ export default {
|
|
data: function() {
|
|
data: function() {
|
|
return {
|
|
return {
|
|
dialog: false,
|
|
dialog: false,
|
|
- list: [{ id: '1', title: '菜单1', children: [{ id: '1-1', title: '菜单1-1' }] }],
|
|
|
|
- defaultProps: {
|
|
|
|
- children: 'children',
|
|
|
|
- label: 'title',
|
|
|
|
- },
|
|
|
|
- form: {},
|
|
|
|
- fields: [
|
|
|
|
- // 数据格式:以垂直为主,每个主菜单的所有子菜单及其关系都垂直下来
|
|
|
|
- { label: '上级菜单', required: false, model: 'node', custom: true }, // 虚拟字段
|
|
|
|
- { label: '菜单名称', required: true, model: 'title' },
|
|
|
|
- { label: '菜单路由', required: false, model: 'route' },
|
|
|
|
- ],
|
|
|
|
|
|
+ list: [],
|
|
|
|
+ defaultProps: { children: 'children', hasChildren: 'hasChildren' },
|
|
rules: {
|
|
rules: {
|
|
- title: [{ required: true, message: '请输入菜单名称' }],
|
|
|
|
|
|
+ title: [{ required: true, message: '请输入目录名称' }],
|
|
},
|
|
},
|
|
|
|
+ form: {},
|
|
|
|
+ isNew: true,
|
|
};
|
|
};
|
|
},
|
|
},
|
|
- created() {},
|
|
|
|
|
|
+ created() {
|
|
|
|
+ this.search();
|
|
|
|
+ },
|
|
methods: {
|
|
methods: {
|
|
- toCheck(data) {
|
|
|
|
- console.log(data);
|
|
|
|
- },
|
|
|
|
- toUpdate(node, data) {
|
|
|
|
- console.log(node, data);
|
|
|
|
- },
|
|
|
|
- toAppend(node, data) {
|
|
|
|
- this.toDialog({ node });
|
|
|
|
|
|
+ ...menu(['create', 'update', 'findProject', 'delete', 'fetch']),
|
|
|
|
+ async search() {
|
|
|
|
+ const res = await this.findProject({ project: 'center', type: this.type });
|
|
|
|
+ if (this.$checkRes(res)) {
|
|
|
|
+ if (res.data) {
|
|
|
|
+ this.$set(this, `list`, res.data);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
},
|
|
},
|
|
- append() {
|
|
|
|
- const { node, ...info } = this.form;
|
|
|
|
- if (node) {
|
|
|
|
- this.$refs.tree.append(info, node);
|
|
|
|
|
|
+ async append() {
|
|
|
|
+ let dup = _.cloneDeep(this.form);
|
|
|
|
+ const { _id } = dup;
|
|
|
|
+ let res;
|
|
|
|
+ if (_id) {
|
|
|
|
+ res = await this.update(dup);
|
|
} else {
|
|
} else {
|
|
- this.list.push(info);
|
|
|
|
|
|
+ dup.project = 'center';
|
|
|
|
+ dup.type = this.type || 0;
|
|
|
|
+ if (!dup.sort) dup.sort = 0;
|
|
|
|
+ res = await this.create(dup);
|
|
|
|
+ }
|
|
|
|
+ if (this.$checkRes(res, '操作成功', res.errmsg || '操作失败')) {
|
|
|
|
+ this.toClose();
|
|
|
|
+ this.search();
|
|
}
|
|
}
|
|
- this.toClose();
|
|
|
|
},
|
|
},
|
|
- toRemove(node, data) {
|
|
|
|
- const oval = _.cloneDeep(this.list);
|
|
|
|
|
|
+ async toRemove(data) {
|
|
this.$confirm(`确定删除${data.title}?`, '提示', {
|
|
this.$confirm(`确定删除${data.title}?`, '提示', {
|
|
confirmButtonText: '确定',
|
|
confirmButtonText: '确定',
|
|
cancelButtonText: '取消',
|
|
cancelButtonText: '取消',
|
|
type: 'warning',
|
|
type: 'warning',
|
|
- }).then(() => {
|
|
|
|
- this.$refs.tree.remove(node);
|
|
|
|
- const nval = _.cloneDeep(this.list);
|
|
|
|
- const toUpdate = _.differenceWith(nval, oval, _.isEqual);
|
|
|
|
- console.log(toUpdate);
|
|
|
|
|
|
+ }).then(async () => {
|
|
|
|
+ // 直接更新
|
|
|
|
+ const { _id } = data;
|
|
|
|
+ let res = await this.delete(_id);
|
|
|
|
+ if (this.$checkRes(res, '操作成功', res.errmsg || '操作失败')) {
|
|
|
|
+ this.search();
|
|
|
|
+ }
|
|
});
|
|
});
|
|
},
|
|
},
|
|
- getNodeTitle(form) {
|
|
|
|
- const node = _.get(form, 'node');
|
|
|
|
- if (!node) return '主菜单';
|
|
|
|
- const { data } = node;
|
|
|
|
- return _.get(data, 'title');
|
|
|
|
- },
|
|
|
|
- toDialog(data) {
|
|
|
|
|
|
+ async toDialog(data, type) {
|
|
this.dialog = true;
|
|
this.dialog = true;
|
|
if (_.isObject(data)) {
|
|
if (_.isObject(data)) {
|
|
- this.$set(this, `form`, data);
|
|
|
|
|
|
+ const dup = _.cloneDeep(data);
|
|
|
|
+ if (type !== 'append') {
|
|
|
|
+ const { pid } = dup;
|
|
|
|
+ if (pid) {
|
|
|
|
+ const pres = await this.fetch(pid);
|
|
|
|
+ if (this.$checkRes(pres)) {
|
|
|
|
+ const { title: pname } = pres.data;
|
|
|
|
+ dup.pname = pname;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ this.$set(this, `form`, dup);
|
|
|
|
+ } else {
|
|
|
|
+ const { _id: pid, title: pname } = dup;
|
|
|
|
+ this.$set(this, `form`, { pid, pname });
|
|
|
|
+ }
|
|
}
|
|
}
|
|
},
|
|
},
|
|
toClose() {
|
|
toClose() {
|
|
@@ -129,6 +152,17 @@ export default {
|
|
pageTitle() {
|
|
pageTitle() {
|
|
return `${this.$route.meta.title}`;
|
|
return `${this.$route.meta.title}`;
|
|
},
|
|
},
|
|
|
|
+ type() {
|
|
|
|
+ return this.$route.query.type;
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ watch: {
|
|
|
|
+ type: {
|
|
|
|
+ handler(val) {
|
|
|
|
+ if (val) this.search();
|
|
|
|
+ },
|
|
|
|
+ immediate: true,
|
|
|
|
+ },
|
|
},
|
|
},
|
|
metaInfo() {
|
|
metaInfo() {
|
|
return { title: this.$route.meta.title };
|
|
return { title: this.$route.meta.title };
|