lrf402788946 4 éve
szülő
commit
965c98351f
6 módosított fájl, 602 hozzáadás és 73 törlés
  1. 14 2
      src/router/index.js
  2. 8 0
      src/store/index.js
  3. 1 0
      src/views/home.vue
  4. 105 71
      src/views/menu/index.vue
  5. 222 0
      src/views/role/index.vue
  6. 252 0
      src/views/user/index.vue

+ 14 - 2
src/router/index.js

@@ -217,10 +217,22 @@ const system = [
   },
   {
     path: '/menu',
-    name: 'setting',
-    meta: { title: '系统菜单' },
+    name: 'menu',
+    meta: { title: '系统目录' },
     component: () => import('@/views/menu/index.vue'),
   },
+  {
+    path: '/role',
+    name: 'role',
+    meta: { title: '角色-权限' },
+    component: () => import('@/views/role/index.vue'),
+  },
+  {
+    path: '/user',
+    name: 'user',
+    meta: { title: '用户管理' },
+    component: () => import('@/views/user/index.vue'),
+  },
 ];
 const newPlan = [
   {

+ 8 - 0
src/store/index.js

@@ -45,6 +45,10 @@ import cerconfirm from '@frame/store/cerconfirm';
 import experience from '@frame/store/experience';
 import talented from '@frame/store/talented';
 import mission from '@frame/store/mission';
+import menu from '@frame/store/auth/menu';
+import role from '@frame/store/auth/role';
+import user from '@frame/store/auth/user';
+import userMenu from '@frame/store/auth/userMenu';
 import * as ustate from '@frame/store/user/state';
 import * as umutations from '@frame/store/user/mutations';
 import * as dostate from '@frame/store/setting/state';
@@ -102,6 +106,10 @@ export default new Vuex.Store({
     experience,
     talented,
     mission,
+    menu,
+    role,
+    user,
+    userMenu,
   },
   state: { ...ustate, ...dostate },
   mutations: { ...umutations, ...domutations },

+ 1 - 0
src/views/home.vue

@@ -45,6 +45,7 @@ export default {
     };
   },
   created() {
+    this.test();
     this.search();
   },
   methods: {

+ 105 - 71
src/views/menu/index.vue

@@ -1,41 +1,52 @@
 <template>
   <div id="index">
     <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-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-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-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>
-    <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 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 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-button type="primary" @click="append">保存</el-button>
@@ -50,6 +61,7 @@ const _ = require('lodash');
 import detailFrame from '@frame/layout/admin/detail-frame';
 import dataForm from '@frame/components/form';
 import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: menu } = createNamespacedHelpers('menu');
 export default {
   name: 'index',
   props: {},
@@ -57,66 +69,77 @@ export default {
   data: function() {
     return {
       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: {
-        title: [{ required: true, message: '请输入菜单名称' }],
+        title: [{ required: true, message: '请输入目录名称' }],
       },
+      form: {},
+      isNew: true,
     };
   },
-  created() {},
+  created() {
+    this.search();
+  },
   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 {
-        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}?`, '提示', {
         confirmButtonText: '确定',
         cancelButtonText: '取消',
         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;
       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() {
@@ -129,6 +152,17 @@ export default {
     pageTitle() {
       return `${this.$route.meta.title}`;
     },
+    type() {
+      return this.$route.query.type;
+    },
+  },
+  watch: {
+    type: {
+      handler(val) {
+        if (val) this.search();
+      },
+      immediate: true,
+    },
   },
   metaInfo() {
     return { title: this.$route.meta.title };

+ 222 - 0
src/views/role/index.vue

@@ -0,0 +1,222 @@
+<template>
+  <div id="index">
+    <detail-frame :title="pageTitle">
+      <el-row type="flex" :gutter="20">
+        <el-col :span="10">
+          <el-card :body-style="cardStyle">
+            <template #header>
+              <el-row type="flex" justify="space-between" align="middle">
+                <el-col :span="4">角色</el-col>
+                <el-col :span="4">
+                  <el-button type="primary" size="small" @click="toAdd">添加角色</el-button>
+                </el-col>
+              </el-row>
+            </template>
+            <el-table :data="roleList" style="width: 100%" border stripe size="small">
+              <el-table-column align="center" prop="name" label="名称">
+                <template v-slot="{ row }">
+                  <div v-if="!row.toEdit">{{ row.name }}</div>
+                  <div v-else>
+                    <el-input v-model="row.name" size="small"></el-input>
+                  </div>
+                </template>
+              </el-table-column>
+              <el-table-column align="center" prop="type" label="类型代码">
+                <template v-slot="{ row }">
+                  <div v-if="!row.toEdit">{{ row.type }}</div>
+                  <div v-else>
+                    <el-input v-model="row.type" size="small"></el-input>
+                  </div>
+                </template>
+              </el-table-column>
+              <el-table-column align="center" prop="name" label="操作">
+                <template v-slot="{ row }">
+                  <el-row type="flex" justify="space-around" align="middle">
+                    <el-col :span="4">
+                      <el-button v-if="!row.toEdit" type="text" @click="toUpdate(row)">修改</el-button>
+                      <el-button v-else type="text" style="color:#67C23A" @click="toSave(row)">保存</el-button>
+                    </el-col>
+                    <template v-if="row.id">
+                      <el-col :span="4">
+                        <el-button type="text" style="color:#909399" @click="toSetRoleMenu(row)">权限</el-button>
+                      </el-col>
+                      <el-col :span="4">
+                        <el-button v-if="!row.disabled" type="text" style="color:#F56C6C" @click="changeDisable(row, true)">禁用</el-button>
+                        <el-button v-else type="text" style="color:#67C23A" @click="changeDisable(row, false)">启用</el-button>
+                      </el-col>
+                      <el-col :span="4">
+                        <el-button type="text" style="color:#F56C6C" @click="toDelete(row)">删除</el-button>
+                      </el-col>
+                    </template>
+                  </el-row>
+                </template>
+              </el-table-column>
+            </el-table>
+          </el-card>
+        </el-col>
+        <el-col :span="14">
+          <el-card header="权限" :body-style="cardStyle">
+            <template #header>
+              <el-row type="flex" justify="space-between" align="middle">
+                <el-col :span="4">
+                  权限
+                  <span v-if="selectRole.id"> => {{ selectRole.name }} </span>
+                </el-col>
+                <el-col :span="4">
+                  <el-button type="primary" size="small" v-if="selectRole.id" @click="toSaveMenu">保存 {{ selectRole.name }} 权限</el-button>
+                  <el-button type="danger" size="small" v-else :disabled="true">未选择角色</el-button>
+                </el-col>
+              </el-row>
+            </template>
+            <el-tree
+              :data="menus"
+              ref="tree"
+              node-key="id"
+              :props="defaultProps"
+              :highlight-current="true"
+              show-checkbox
+              default-expand-all
+              :default-checked-keys="isSelect"
+            >
+            </el-tree>
+            <!-- @check-change="toPermission" -->
+          </el-card>
+        </el-col>
+      </el-row>
+    </detail-frame>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+import detailFrame from '@frame/layout/admin/detail-frame';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: menu } = createNamespacedHelpers('menu');
+const { mapActions: role } = createNamespacedHelpers('role');
+export default {
+  name: 'index',
+  props: {},
+  components: { detailFrame },
+  data: function() {
+    return {
+      cardStyle: {
+        height: '600px',
+        overflowY: 'scroll',
+      },
+      menus: [],
+      roleList: [],
+      selectRole: {},
+      isSelect: [],
+      defaultProps: {
+        children: 'children',
+        label: 'title',
+      },
+    };
+  },
+  created() {
+    this.searchRole();
+    this.toFindMenuList();
+  },
+  methods: {
+    ...role(['create', 'update', 'query', 'delete']),
+    ...menu(['findProject']),
+    async searchRole() {
+      const res = await this.query();
+      if (this.$checkRes(res)) {
+        const { data = [] } = res;
+        this.$set(this, `roleList`, data);
+      }
+    },
+    async toFindMenuList() {
+      const res = await this.findProject({ project: 'center' });
+      if (this.$checkRes(res)) {
+        if (res.data) {
+          this.$set(this, `menus`, res.data);
+        }
+      }
+    },
+    // 添加前置
+    toAdd() {
+      this.roleList.push({ toEdit: true });
+    },
+    // 修改前置
+    toUpdate(row) {
+      const index = _.findIndex(this.roleList, row);
+      if (index >= 0) {
+        this.$set(this.roleList, index, { ...row, toEdit: true });
+      }
+    },
+    // 添加/修改
+    async toSave(data) {
+      const dup = _.cloneDeep(data);
+      const { toEdit, ...info } = dup;
+      if (!toEdit) {
+        console.warn('不能保存未处于编辑状态的数据');
+        return;
+      }
+      const id = _.get(info, `id`);
+      let res;
+      if (id) {
+        res = await this.update(info);
+      } else {
+        info.project = 'center';
+        res = await this.create(info);
+      }
+      if (this.$checkRes(res, '保存成功', res.errmsg || '保存失败')) {
+        this.searchRole();
+      }
+    },
+    // 禁用/启用
+    async changeDisable(data, disabled) {
+      let duplicate = _.cloneDeep(data);
+      duplicate.disabled = disabled;
+      const res = await this.update(duplicate);
+      let word = disabled === true ? '禁用' : '启用';
+      if (this.$checkRes(res, `${word}成功`, res.errmsg || `${word}失败`)) {
+        this.searchRole();
+      }
+    },
+    // 删除
+    async toDelete(data) {
+      this.$confirm(`确定删除${data.name}?`, '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+      }).then(async () => {
+        // 直接更新
+        const { _id } = data;
+        let res = await this.delete(_id);
+        if (this.$checkRes(res, '删除成功', res.errmsg || '删除失败')) {
+          this.searchRole();
+        }
+      });
+    },
+    // 设置该角色已选择的权限
+    toSetRoleMenu(data) {
+      const { menu = [] } = data;
+      this.$set(this, `selectRole`, _.cloneDeep(data));
+      this.$refs.tree.setCheckedKeys(menu);
+    },
+    async toSaveMenu() {
+      const selected = this.$refs.tree.getCheckedKeys();
+      let duplicate = _.cloneDeep(this.selectRole);
+      duplicate.menu = selected;
+      const res = await this.update(duplicate);
+      if (this.$checkRes(res, `权限设置成功`, res.errmsg || `权限设置失败`)) {
+        this.searchRole();
+      }
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 252 - 0
src/views/user/index.vue

@@ -0,0 +1,252 @@
+<template>
+  <div id="index">
+    <detail-frame :title="pageTitle" v-if="view == 'list'">
+      <el-row type="flex" justify="end" align="middle">
+        <el-col :span="4">
+          <el-button type="primary" size="small" @click="dialog = true">添加管理员用户</el-button>
+        </el-col>
+      </el-row>
+      <data-table
+        :fields="fields"
+        :data="list"
+        :opera="opera"
+        :total="total"
+        :toFormat="toFormat"
+        @query="search"
+        @edit="toEdit"
+        @freeze="data => toStatus(data, '2')"
+        @unfreeze="data => toStatus(data, '1')"
+        @toRoleMenu="toRoleMenu"
+      >
+        <template #options="{item}">
+          <template v-if="item.prop === 'type'">
+            <el-option v-for="(i, index) in roleList" :key="`role-${index}`" :label="i.name" :value="i.type"></el-option>
+          </template>
+        </template>
+        <template #custom="{item,row}">
+          <template v-if="item.prop === 'openid'">
+            <span :style="{ color: `${row[item.prop] ? '#67C23A' : '#F56C6C'}` }">{{ row[item.prop] ? '已绑定' : '未绑定' }}</span>
+          </template>
+        </template>
+      </data-table>
+    </detail-frame>
+    <detail-frame :title="roleTitle" :returns="() => (view = 'list')" v-else>
+      <el-card header="权限" :body-style="cardStyle">
+        <template #header>
+          <el-row type="flex" justify="space-between" align="middle">
+            <el-col :span="4">
+              权限
+            </el-col>
+            <el-col :span="4">
+              <el-button type="primary" size="small" @click="toSaveMenu">保存</el-button>
+            </el-col>
+          </el-row>
+        </template>
+        <el-tree
+          :data="menus"
+          ref="tree"
+          node-key="id"
+          :props="defaultProps"
+          :highlight-current="true"
+          show-checkbox
+          default-expand-all
+          :default-checked-keys="isSelect"
+        >
+        </el-tree>
+      </el-card>
+    </detail-frame>
+
+    <el-dialog :visible.sync="dialog" title="添加管理员" @close="toClose" width="30%" :destroy-on-close="true">
+      <data-form :data="form" :fields="formFields" :rules="rules" @save="toSave"> </data-form>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+import dataForm from '@frame/components/form';
+import dataTable from '@frame/components/filter-page-table';
+import detailFrame from '@frame/layout/admin/detail-frame';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: users } = createNamespacedHelpers('user');
+const { mapActions: role } = createNamespacedHelpers('role');
+const { mapActions: menu } = createNamespacedHelpers('menu');
+const { mapActions: userMenu } = createNamespacedHelpers('userMenu');
+export default {
+  name: 'index',
+  props: {},
+  components: { dataTable, detailFrame, dataForm },
+  data: function() {
+    return {
+      view: 'list',
+      opera: [
+        {
+          label: '用户权限',
+          method: 'toRoleMenu',
+        },
+        {
+          label: '编辑',
+          method: 'edit',
+        },
+        {
+          label: '冻结账号',
+          display: i => i.status !== '2',
+          method: 'freeze',
+        },
+        {
+          label: '解除冻结',
+          display: i => !(i.status !== '2'),
+          method: 'unfreeze',
+        },
+      ],
+      fields: [
+        { label: '用户名', prop: 'name', filter: true },
+        { label: '登录名', prop: 'mobile' },
+        { label: '密码', prop: 'passwd' },
+        { label: '是否绑定微信', prop: 'openid', custom: true },
+        { label: '角色', prop: 'type', format: true, filter: 'select' },
+        { label: '备注', prop: 'remark' },
+        { label: '状态', prop: 'status', format: i => (i !== '2' ? '使用中' : '冻结') },
+      ],
+      dialog: false,
+      form: {},
+      formFields: [
+        { label: '用户名', required: false, model: 'name' },
+        { label: '登录名', required: true, model: 'mobile' },
+        { label: '密码', required: true, model: 'passwd' },
+        { label: '备注', required: false, model: 'remark', type: 'textarea' },
+      ],
+      rules: {
+        mobile: [{ required: true, message: '请输入登陆名' }],
+        passwd: [{ required: true, message: '请输入密码' }],
+      },
+      list: [],
+      total: 0,
+      roleList: [],
+      // 角色权限部分
+      cardStyle: {
+        height: '600px',
+        overflowY: 'scroll',
+      },
+      roleTitle: '',
+      menus: [],
+      isSelect: [],
+      defaultProps: {
+        children: 'children',
+        label: 'title',
+      },
+      selectUser: {},
+    };
+  },
+  created() {
+    this.toGetRoleList();
+    this.search();
+  },
+  methods: {
+    ...users(['create', 'update', 'query', 'update']),
+    ...role({ getRoleList: 'query', roleMenu: 'roleMenu' }),
+    ...userMenu({ createUserMenu: 'create' }),
+    // 查找角色
+    async search({ skip = 0, limit = 10, ...info } = {}) {
+      const res = await this.query({ skip, limit, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, `list`, res.data);
+        this.$set(this, `total`, res.total);
+      }
+    },
+    //编辑角色
+    toEdit({ data }) {
+      this.$set(this, `form`, _.cloneDeep(data));
+      this.dialog = true;
+    },
+    //添加/修改角色
+    async toSave({ data }) {
+      const { _id } = data;
+      let res;
+      if (_id) {
+        res = this.update(data);
+      } else {
+        data.type = '0';
+        res = this.create(data);
+      }
+      if (this.$checkRes(res, `操作成功`, res.errmsg || '操作失败')) {
+        this.toClose();
+        this.search();
+      }
+    },
+    // 更换角色状态
+    async toStatus({ data }, status) {
+      data.status = status;
+      const res = this.update(data);
+      const word = status === '2' ? '冻结' : '解冻';
+      if (this.$checkRes(res, `${word}成功`, res.errmsg || `${word}失败`)) {
+        this.search();
+      }
+    },
+    //获取指定用户的菜单,进入该用户权限编辑页面
+    async toRoleMenu({ data }) {
+      if (!data.type) {
+        this.$message.error('未找到用户角色');
+        return;
+      }
+      const { name, _id } = data;
+      let obj = { type: data.type, project: 'center', userid: _id };
+      const res = await this.roleMenu(obj);
+      if (this.$checkRes(res)) {
+        let { selected, menu } = res.data;
+        this.$set(this, `menus`, menu);
+        this.$set(this, `isSelect`, selected);
+        this.$set(this, `selectUser`, _.cloneDeep(data));
+        this.$set(this, `roleTitle`, `${name} => 权限设置`);
+        this.view = 'tree';
+      }
+    },
+    // 保存该用户非角色权限
+    async toSaveMenu() {
+      // 所有已经选择的菜单(包括角色部分)
+      const selected = this.$refs.tree.getCheckedKeys();
+      let duplicate = _.cloneDeep(this.isSelect);
+      const needSave = _.difference(selected, duplicate);
+      let obj = { project: 'center', menu: needSave };
+      if (!this.selectUser._id) {
+        this.$message.error('未找到该用户的信息');
+        return;
+      }
+      obj.userid = this.selectUser._id;
+      const res = await this.createUserMenu(obj);
+      this.$checkRes(res, '保存成功', res.errmsg || '保存失败');
+    },
+    toFormat({ model, value }) {
+      if (model === 'type') {
+        const r = this.roleList.find(f => f.type == value);
+        if (r) {
+          return r.name || '';
+        } else {
+          return '未设置的角色';
+        }
+      }
+    },
+    toClose() {
+      this.dialog = false;
+      this.form = {};
+    },
+    async toGetRoleList() {
+      const res = await this.getRoleList();
+      if (this.$checkRes(res)) {
+        this.$set(this, `roleList`, res.data);
+      }
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped></style>