vue-day10

vue项目-day02

1-项目基础文件

1.1-element封装

/utils/element.js

// 全部导入
import Vue from 'vue';
import element from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
// 注册
Vue.use(element);

// 封装一个成功提示
Vue.prototype.$success=function(message){
    this.$message({
        type:'success',
        message
    });
}    

// 封装一个失败提示
Vue.prototype.$error=function(message){
    this.$message({
        type:'error',
        message
    });
}    

// 确认提示框
Vue.prototype.$myConfirm=function(callback){
    this.$confirm('确认删除?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        // 确认之后的逻辑操作
        callback&&callback();
      }).catch(() => {
        // 取消之后的逻辑操作       
      });
}

1.2-路由模块

/router/index.js

import Vue from 'vue';
import Router from 'vue-router';

const Login=()=>import('../pages/Login');
const Layout=()=>import('../pages/Layout');
// 菜单管理
const Menu=()=>import('../pages/menu/Index');
// 角色管理
const Role=()=>import('../pages/role/Index');
// 管理员管理
const Admin=()=>import('../pages/admin/Index');


Vue.use(Router);

// 定义路由规则
const  routes= [
  {
    path: '/login',
    name: 'Login',
    component: Login,
    meta:{
      title:'管理员登录'
    }
  },
  {
    path:'/',
    component:Layout,
    meta:{
      title:'小U商城后台管理系统'
    },
    children:[
      {
        path:'/menu',
        component:Menu,
        meta:{
          title:'菜单管理'
        }
      },
      {
        path:'/role',
        component:Role,
        meta:{
          title:'角色管理'
        }
      },
      {
        path:'/admin',
        component:Admin,
        meta:{
          title:'管理员管理'
        }
      }
    ]
  }
];

const router=new Router({
  routes
});

// 路由导航守卫
router.beforeEach(function(to,from,next){
  // 如果用户访问的是非登录页面
  if(to.path!=='/login'){
    // 读取本地存储
    const loginInfo=JSON.parse(localStorage.getItem('loginInfo')||'{}');
    // 如果没有登录凭证
    if(!loginInfo.token){
      return next('/login');
    }
  }
  next();
  // 动态设置页面标题
  document.title=to.meta.title;
});

export default router;

1.3-事件中心vm

utils/vm.js

// 导入vue
import Vue from 'vue';
// 创建一个空vue实例
const vm=new Vue();
// 导出
export default vm;

2-菜单管理

2.1-菜单添加&编辑

pages/menu/Modal.vue

<template>
  <el-dialog @close="resetForm" :title="formData.id>0?'编辑':'新增'" :visible.sync="info.isShow">
    <el-form ref="menuForm" :model="formData" :rules="rules" label-width="60px">
      <el-form-item label="类型" prop="type">
        <el-radio-group v-model="formData.type">
            <el-radio :label="1">目录</el-radio>
            <el-radio :label="2">菜单</el-radio>
        </el-radio-group>
      </el-form-item>

      <el-form-item label="上级" v-if="formData.type===2" prop="pid">
        <el-select placeholder="请选择" v-model="formData.pid">
            <el-option :value="0" label="顶级菜单"></el-option>
            <el-option
            v-for="item in menuList"
            :key="item.id"
            :label="item.title"
            :value="item.id">
            </el-option>
        </el-select>
      </el-form-item>

      <el-form-item label="名称" prop="title">
        <el-input placeholder="菜单标题" v-model="formData.title"></el-input>
      </el-form-item> 

      <el-form-item label="图标" v-if="formData.type===1" prop="icon">
        <el-input placeholder="图标" v-model="formData.icon"></el-input>
      </el-form-item> 

      <el-form-item label="地址" v-if="formData.type===2" prop="url">
        <el-input placeholder="地址" v-model="formData.url"></el-input>
      </el-form-item> 

      <el-form-item label="状态" prop="status">
        <el-radio-group v-model="formData.status">
            <el-radio :label="1">正常</el-radio>
            <el-radio :label="2">禁用</el-radio>
        </el-radio-group>
      </el-form-item>

    </el-form>
    <div slot="footer" class="dialog-footer">
      <el-button @click="info.isShow = false">取 消</el-button>
      <el-button type="primary" @click="submit">确 定</el-button>
    </div>
  </el-dialog>
</template>

<script>
import { mapState } from 'vuex';
export default {
  computed:{
      ...mapState({menuList:state=>state.menu.menuList})
  },
  // 接收父组件传递过来的数据 
  props: ['info'],
  data() {
    return {
       // 和表单元素进行绑定 
      formData: {
          id:0,
          pid:0,
          title:'',
          icon:'',
          status:'',
          type:1,
          url:''
      },
      // 表单校验规则  
      rules:{
         title:{required:true,message:'请输入名称',trigger:'blur'},
         status:{required:true,message:'请选择状态',trigger:'blur'}
      }
    };
  },
  methods:{
      //   表单提交
      submit(){
          this.$refs.menuForm.validate(valid=>{
              if(valid){
                const url=this.formData.id>0?'/menuedit':'/menuadd';
                //  提交表单
                this.$http.post(url,this.formData).then(res=>{
                    if(res.code===200){
                        this.$success(res.msg);
                        // 1-关闭对话框组件
                        this.info.isShow=false;
                        // 2-更新数据列表
                        this.$emit('updateList')
                    }else{
                        this.$error(res.msg);
                    }
                })
              }
          });
      },
      // 更新formData
      setFormData(obj){
        this.formData={...obj}
      },
      resetForm(){
          //   重置表单
          this.$refs.menuForm.resetFields();
          this.formData={
            pid:0,
            title:'',
            icon:'',
            status:'',
            type:1,
            url:''
          }
      }
      
  }
};
</script>

<style>
</style>

2.2-菜单删除

pages/menu/Index.vue

<el-table-column label="操作">
    <template v-slot="props">
        <el-button @click="del(props.row.id)" circle size="mini" icon="el-icon-delete" type="danger"></el-button>
    </template>
</el-table-column>
export default {
    methods:{
        del(id){
          this.$myConfirm(()=>{
            // 发请求删除据
            this.$http.post('/menudelete',{id}).then(res=>{
               if(res.code===200){
                 this.$success(res.msg);
                 // 更新数据列表
                 this.getMenuListAction();
                 return false;
               } 
               this.$error(res.msg);
            })
          });
    }
}

3-角色管理

3.0-数据层封装

/request/role.js

import axios from '../utils/http';
// 获取菜单列表
export async function getMenuList(){
   const res=await axios.get('/menulist?istree=1');
   if(res.code===200){
      return res.list;  
   }
   return false;
}

/store/modules/role.js

// 导入数据请求方法
import { getRoleList } from '../../request/role'
export default {
    // 开启独立命名空间
    namespaced:true,
    state(){
        return {
            // 角色列表
            roleList:[]
        }
    },
    mutations:{
        // 初始化角色列表
        // state: 系统自动注入的参数
        // list:额外参数(是异步action通过数据接口获取的角色列表)
        roleListInit(state,list){
            state.roleList=list;
        }
    },
    actions:{
        getRoleListAction({commit}){
            getRoleList().then(res=>{
                if(res){
                    // 通过commit调用roleListInit
                    commit('roleListInit',res);
                }
            })
        }
    }
}

/store/index.js

// 1-导入
import Vue from 'vue';
import Vuex from 'vuex';

// 2-注册
Vue.use(Vuex);

// 导入子模块
import menu from './modules/menu';
import role from './modules/role';
import admin from './modules/admin'


// 3-创建数据存储对象
const store=new  Vuex.Store({
    state:{},
    mutations:{},
    getter:{},
    actions:{},
    modules:{
        menu,
        role,
        admin
    }
});

// 4-导出
export default store;

3.1-角色列表

pages/role/Inde.vue

<template>
  <el-card>
    <el-button
      @click="info.isShow=!info.isShow"
      type="primary"
      icon="el-icon-circle-plus-outline"
    >新增</el-button>
    <el-divider />
    <!-- 调用列表组件List -->
    <List :roleList="roleList" @updateList="updateList"/>
    <!-- 调用表单组件Modal -->
    <Modal :info="info" @updateList="updateList" />
  </el-card>
</template>

<script>
// 导入子组件
import Modal from "./Modal";
import List from "./List";
import { mapState, mapActions } from "vuex";
export default {
  components: {
    Modal,
    List
  },
  computed: {
    ...mapState({
      roleList: state => state.role.roleList
    })
  },
  methods: {
    ...mapActions("role", ["getRoleListAction"]),
    // 自定义事件updateList的处理函数
    updateList() {
      // 更新数据列表
      this.getRoleListAction();
    }
  },
  created() {
    this.getRoleListAction();
  },
  data() {
    return {
      info: {
        // 控制对话框的显示状态
        isShow: false
      }
    };
  }
};
</script>

pages/role/List.vue

<template>
  <el-table :data="roleList" style="width: 100%">
    <el-table-column prop="id" label="id" min-width="80"></el-table-column>
    <el-table-column prop="rolename" label="角色名称" min-width="180"></el-table-column>
    <el-table-column prop="status" label="状态" min-width="180">
      <template v-slot="props">
        <el-tag type="success" v-if="props.row.status===1">正常</el-tag>
        <el-tag type="danger" v-else>禁用</el-tag>
      </template>
    </el-table-column>
    <el-table-column label="操作" min-width="180">
      <template v-slot="props">
        <el-button @click="edit(props.row)" size="mini" circle icon="el-icon-edit" type="success"></el-button>
        <el-button
          @click="del(props.row.id)"
          size="mini"
          circle
          icon="el-icon-delete"
          type="danger"
        ></el-button>
      </template>
    </el-table-column>
  </el-table>
</template>

<script>
// 导入事件中心
import vm from "../../utils/vm";
export default {
  props: ["roleList"],
  methods: {
    del(id) {
      this.$myConfirm(()=>{
        // 1-发送数据请求
        this.$http.post('/roledelete',{id}).then(res=>{
          if(res.code===200){
            this.$success(res.msg);
             // 2-更新数据列表
             this.$emit('updateList');
          }else{
            this.$error(res.msg);
          }
        })
       
      })
    },
    // 角色编辑
    edit(obj) {
      // 通过vm.$emit()将待编辑的数据对象传递给Modal
      vm.$emit("sendData", { ...obj });
    }
  }
};
</script>

3.2-角色添加&编辑

pages/role/Modal.vue

<template>
  <el-dialog @close="reset" :title="formData.id>0?'编辑':'新增'" :visible.sync="info.isShow">
    <el-form label-width="80px" :model="formData" :rules="rules" ref="formRef">
      <el-form-item label="角色名称" prop="rolename">
        <el-input placeholder="角色名称" v-model="formData.rolename"></el-input>
      </el-form-item>
      <el-form-item label="角色权限" prop="menus">
        <el-tree
          ref="treeRef"
          :data="menuList"
          show-checkbox
          node-key="id"
          default-expand-all
          :props="defaultProps"
        ></el-tree>
      </el-form-item>
      <el-form-item label="角色状态" prop="status">
        <el-radio-group v-model="formData.status">
          <el-radio :label="1">正常</el-radio>
          <el-radio :label="2">禁用</el-radio>
        </el-radio-group>
      </el-form-item>
    </el-form>
    <div slot="footer" class="dialog-footer">
      <el-button @click="reset">取 消</el-button>
      <el-button type="primary" @click="submit">确 定</el-button>
    </div>
  </el-dialog>
</template>

<script>
// 导入事件中心
import vm from '../../utils/vm'
import { mapState, mapActions } from "vuex";
export default {
  props: ["info"],
  created() {
    // 初始化数据menuList
    this.getMenuListAction();
    // 监听自定义事件
    vm.$on('sendData',(obj)=>{
      // 1-更新this.formData
      this.formData=obj;
      // 2-显示对话框组件
      this.info.isShow=true;
      // 3-勾选当前角色操作权限
      setTimeout(() => {
         this.$refs.treeRef.setCheckedKeys(this.formData.menus.split(',')); 
      }, 100);
    })
  },
  computed: {
    ...mapState({
      menuList: state => state.menu.menuList
    })
  },
  methods: {
    ...mapActions("menu", ["getMenuListAction"]),
    // 表单提交
    submit() {
      // 终极的表单校验
      this.$refs.formRef.validate(valid => {
        if (valid) {
          // 1-获取用户勾选的节点
          const keys=this.$refs.treeRef.getCheckedKeys().join(',');
          // 2-手动更新formData.menus
          this.formData.menus=keys;
          // 3-提交数据
          const url=this.formData.id>0?'/roleedit':'/roleadd'
          this.$http.post(url,this.formData).then(res=>{
            if(res.code===200){
              this.$success(res.msg);
              // 通过自定义事件通知父组件更新数据列表
              this.$emit('updateList');
              // 重置数据
              this.reset();
              return false;
            }
            this.$error(res.msg);
          });
        } 
      });
    },
    // 数据重置
    reset(){
      // 1-重置表单
      this.formData= {
        rolename: "", // 角色名称
        status: "", // 角色状态
        menus: "" // 角色权限
      }
      // 清空树形组件的勾选项
      this.$refs.treeRef.setCheckedKeys([]);
      // 2-关闭对话框
      this.info.isShow=false;
    }
  },
  data() {
    // 自定义表单校验规则方法
    var validMenus = (rule, value, callback) => {
      const keys = this.$refs.treeRef.getCheckedKeys();
      if (keys.length <= 0) {
        return callback(new Error("请选择操作权限"));
      }
      //  表示表单校验通过
      callback();
    };

    return {
      isShow: true,
      // 属性控件的相关属性值
      defaultProps: {
        children: "children",
        label: "title"
      },
      // 和表单元素进行双向数据绑定
      formData: {
        id:0,
        rolename: "", // 角色名称
        status: "", // 角色状态
        menus: "" // 角色权限
      },
      // 表单校验规则
      rules: {
        rolename: {
          required: true,
          message: "请输入角色名称",
          trigger: "blur"
        },
        status: { required: true, message: "请选择状态", trigger: "blur" },
        // 自定义表单校验
        menus:{validator:validMenus,trigger:'blur'}
      }
    };
  }
};
</script>

3.3-角色删除

pages/role/List.vue

<el-table-column label="操作" min-width="180">
    <template v-slot="props">
        <el-button
                   @click="del(props.row.id)"
                   size="mini"
                   circle
                   icon="el-icon-delete"
                   type="danger"
                   >
        </el-button>
    </template>
</el-table-column>
export default {
      methods: {
            del(id) {
              this.$myConfirm(()=>{
                // 1-发送数据请求
                this.$http.post('/roledelete',{id}).then(res=>{
                  if(res.code===200){
                    this.$success(res.msg);
                     // 2-更新数据列表
                     this.$emit('updateList');
                  }else{
                    this.$error(res.msg);
                  }
                })

              })
            }
      }
}

4-管理员管理

4.0-数据层封装

/request/admin.js

// 导入axios
import axios from '../utils/http';

// 获取管理员列表
// params={page:'页码',size:'每页显示数据条数'}
export async function getAdminList(params){
    const res=await axios.get('/userlist',{
        params
    });
    if(res.code===200){
        return res.list;
    }
    return false;
}

// 获取数据总条数
export async function getAdminTotal(){
    const res=await axios.get('/usercount');
    if(res.code===200){
        return res.list[0].total;
    }
    return false;
}

/store/modules/admin.js

// 导入数据请求方法
import { getAdminList,getAdminTotal } from '../../request/admin';
export default {
    // 开启独立命名空间
    namespaced:true,
    state(){
        return {
            // 管理员列表
            adminList:[],
            // 管理员总数
            adminTotal:0,
        }
    },
    mutations:{
        // 初始化adminList
        adminListInit(state,list){
            state.adminList=list;
        },
        // 初始化adminTotal
        adminTotalInit(state,total){
            state.adminTotal=total;
        }
    },  
    actions:{
        // parmas={page:'页码',size:'每页显示的数据条数'}
        getAdminListAction({commit},parmas){
            getAdminList(parmas).then(list=>{
                // 通过commit方法调用同步mutation方法adminListInit实现更新数据
                if(list){
                    commit('adminListInit',list);
                }
            });
        },
        getAdminTotalAction({commit}){
            getAdminTotal().then(total=>{
                // 通过commit方法调用同步mutation方法adminListInit实现更新数据
                if(total){
                    commit('adminTotalInit',total);
                }
            });
        },
    }
}

4.1-管理员列表

pages/admin/Index.vue

<template>
  <el-card>
    <el-button @click="info.isShow=!info.isShow" icon="el-icon-circle-plus-outline" type="primary">新增</el-button>
    <el-divider />
    <!-- 通过自定义属性, 向子组件传递数据 -->
    <!-- 列表组件 -->
    <List @updatePage="updatePage" :size="size" :adminList="adminList" :adminTotal="adminTotal" />
    <!-- 表单组件 -->
    <Modal @updateList="updateList" :info="info"/>
  </el-card>
</template>

<script>
// 导入vuex的辅助方法
import { mapState, mapActions } from "vuex";
// 导入列表组件
import List from "./List";
import Modal from "./Modal";

export default {
  data() {
    return {
      info: {
        // 控制对话框组件的显示状态
        isShow: false
      },
      // 页码
      page: 1,
      // 每页显示的数据条数
      size: 2
    };
  },
  computed: {
    ...mapState({
      adminList: state => state.admin.adminList,
      adminTotal: state => state.admin.adminTotal
    })
  },
  methods: {
    ...mapActions("admin", ["getAdminListAction", "getAdminTotalAction"]),
    // 自定义事件updatePage处理函数
    updatePage(page) {
      // 1-更新页码
      this.page = page;
      // 2-重新请求数据列表
      this.getAdminListAction({ page: this.page, size: this.size });
    },
    // 自定义事件updateList的处理方法
    updateList(){
        // 更新数据列表
        this.getAdminListAction({page:this.page,size:this.size});
        // 更新数据总条数
        this.getAdminTotalAction();
    }
  },
  components: { List, Modal },
  created() {
    this.getAdminListAction({ page: this.page, size: this.size });
    this.getAdminTotalAction();
  }
};
</script>

/pages/admin/List.vue

<template>
  <div>
    <el-table :data="adminList" style="width: 100%">
      <el-table-column prop="id" label="id" min-width="80"></el-table-column>
      <el-table-column prop="rolename" label="角色" min-width="180"></el-table-column>
      <el-table-column prop="username" label="账号" min-width="180"></el-table-column>
      <el-table-column prop="status" label="状态" min-width="180">
         <template v-slot="props">
           <el-tag type="success" v-if="props.row.status===1">正常</el-tag>
           <el-tag type="danger" v-else>禁用</el-tag>
         </template>
      </el-table-column>
      <el-table-column label="操作" min-width="180">
        <template>
          <el-button size="mini" circle type="success" icon="el-icon-edit"></el-button>
          <el-button size="mini" circle type="danger" icon="el-icon-delete"></el-button>
        </template>
      </el-table-column>

    </el-table>
    <!-- 
      total:数据总条数
      page-size: 每页显示的数据条数
      current-change: 分页按钮点击事件
    -->
    <el-pagination @current-change="pageUpdate" :page-size="size" background layout="prev, pager, next" :total="adminTotal"></el-pagination>
  </div>
</template>

<script>
export default {
  props:['adminTotal','adminList','size'],
  data() {
    return {}
  },
  methods:{
    //  分页按钮被点击的处理函数
    // page: 分页按钮的页码, 系统自动注入
    pageUpdate(page){
      // 通过this.$emit()将最新页码值传递给父组件Index
      this.$emit('updatePage',page);
    }
  }
};
</script>

4.2-管理员添加

pages/admin/Modal.vue

<template>
  <el-dialog @close="reset" title="新增" :visible.sync="info.isShow">
    <el-form ref="formRef" label-width="80px" :model="formData" :rules="rules">
      <el-form-item label="角色" prop="roleid">
        <el-select v-model="formData.roleid">
          <el-option
            v-for="item in roleList"
            :key="item.id"
            :label="item.rolename"
            :value="item.id"
          ></el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="账号" prop="username">
        <el-input placeholder="账号" v-model="formData.username"></el-input>
      </el-form-item>
      <el-form-item label="密码" prop="password">
        <el-input placeholder="密码" v-model="formData.password" type="password"></el-input>
      </el-form-item>
      <el-form-item label="状态" prop="status">
        <el-radio-group v-model="formData.status">
          <el-radio :label="1">正常</el-radio>
          <el-radio :label="2">禁用</el-radio>
        </el-radio-group>
      </el-form-item>
    </el-form>
    <div slot="footer" class="dialog-footer">
      <el-button>取 消</el-button>
      <el-button type="primary" @click="submit">确 定</el-button>
    </div>
  </el-dialog>
</template>

<script>
// 导入辅助方法
import { mapState, mapActions } from "vuex";
export default {
  computed: {
    ...mapState({
      roleList: state => state.role.roleList
    })
  },
  props: ["info"],
  data() {
    return {
      // 表单数据模型
      formData: {
        // 角色id
        roleid: '',
        //  账号
        username: "",
        // 密码
        password: "",
        // 状态
        status: ""
      },
      // 表单校验规则对象
      rules: {
        roleid: { required: true, message: "请选择角色", trigger: "blur" },
        username: { required: true, message: "请输入账号", trigger: "blur" },
        password: { required: true, message: "请输入密码", trigger: "blur" },
        status: { required: true, message: "请选择状态", trigger: "blur" }
      }
    };
  },
  methods: {
    ...mapActions("role", ["getRoleListAction"]),
    submit(){
        this.$refs.formRef.validate(valid=>{
            if(valid){
                // 发请求
                this.$http.post('/useradd',this.formData).then(res=>{
                    if(res.code===200){
                        this.$success(res.msg);
                        // 更新数据列表: 通知父组件更新数据列表
                        this.$emit('updateList');
                        // 重置信息
                        this.reset();
                    }else{
                        this.$error(res.msg);
                    }
                    
                })
            }
        });
    },
    // 数据重置
    reset(){
        this.formData={
             // 角色id
            roleid: '',
            //  账号
            username: "",
            // 密码
            password: "",
            // 状态
            status: ""
        }
        // 隐藏对话框组件
        this.info.isShow=false;
    }
  },
  created() {
    this.getRoleListAction();
  }
};
</script>

5-在线文档

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值