资讯详情

【Vue】项目:尚品汇后台管理系统(上)

前言

记录尚品汇后台管理系统的开发过程,包括登录、主页、品牌管理、平台属性管理等功能模块SKU管理、SPU管理、用户管理、角色管理、菜单管理模块。后台管理系统是CMS通过项目实战,内容管理系统的子集可以彻底了解如何实现菜单权限和按钮权限,掌握市场数据的可视化ECharts、V-charts的运用。

主要技术点:Vue-cli、Axios、Vuex、Element-UI、菜单权限、按钮权限、数据可视化、Scss……

由于项目写得太长,编辑器真的卡住了,所以项目分为上、中、下三部分. 【Vue】项目:尚品汇后台管理系统(中) 【Vue】项目:尚品汇后台管理系统(下)


文章目录

  • 前言
  • 一、项目介绍
  • 二、项目配置
  • 三、完成登录业务
  • 四、退出登录业务
  • 五、项目路由的搭建
  • 六、完成品牌管理(tradeMark)静态组件
  • 七、展示品牌管理列表
  • 八、添加品牌,修改品牌静态组件
  • 九、完成品牌添加功能
  • 十、完成品牌修改功能
  • 十一、表格验证功能
  • 十二、删除品牌操作


一、项目介绍

1.后台管理系统项目的开发也是用于信息系统管理的网页。类似于学生管理系统等。

2.后台管理项目有一些模板些模板,方便程序员构建项目框架。

简洁版: https://github.com/PanJiaChen/vue-admin-template (本次使用) 加强版: https://github.com/PanJiaChen/vue-element-admin (如果github可以进不去gitee上下载:https://gitee.com/panjiachen/vue-admin-template?_from=gitee_search)

3.模板文件和文件夹的认知简洁版

  • build ----index.js webpack配置文件【很少修改这个文件】

  • mock ----mock数据文件夹模拟一些假数据mockjs实现,因为在实际开发中,使用的是真实的界面

  • node_modules ------模块依赖于项目

  • public ------ico图标,静态页面,publick一些静态资源经常放置在文件夹中,当项目打包时webpack这个文件夹不会编译,原封不动地打包到dist文件夹里面

  • src -----程序员源代码的位置 -----api文件夹:与请求相关的文件夹: -----assets文件夹:放置一些静态资源(一般共享)aseets文件夹中的静态资源webpack包装时,将进行编译

    -----components文件夹:一般放置非路由组件获取全局组件

    -----icons这个文件夹里面放了一些svg矢量图

    -----layout文件夹:他把一些组件和混合物放在里面

    -----router文件夹:与路由相关的文件夹:

    ----store文件夹:必须是和vuex先关的

    ----style文件夹:与样式先关

    -----utils文件夹:request.js是axios二次包装文件

    -----views文件夹:路由组件放置在里面

  • App.vue:根组件

  • main.js:入口文件

  • permission.js:与导航守卫有关

  • settings:项目配置项文件


二、项目配置

1.首先从github简单项目上下载。

2.原项目不依赖环境,需要运行cmd,cnpm install 依赖环境进行安装。

  • 遇到报错: npm ERR! Cannot set [properties]

image

  • 解决办法: 用cnpm安装

3.运营项目:查看package.json

  • 可以看出,运使用的语句是,npm run dev

  • 遇到报错:* core-js/modules/es. …

  • 解决方案:安装core-js cnpm core-js --save

4.后台管理系统API接口在线文档:

http://39.98.123.211:8170/swagger-ui.html

http://39.98.123.211:8216/swagger-ui.html


三、完成登录业务

1.找到登录业务的位置并修改文本。

2.书写API,将api user.js在线文档中的接口被真实接口取代

// api/user.js中 // 引入axios(axios二次封装) import request from '@/utils/request' // 外露登录接口函数 export function login(data) { 
           return request({ 
             url: '/admin/acl/index/login',     method: 'post',     data   }) } // 获取用户信息的户信息的函数 export function getInfo(token) span class="token punctuation">{
     
       
  return request({ 
        
    url: '/admin/acl/index/info',
    method: 'get',
    params: { 
         token }
  })
}
// 对外暴露退出登录的函数
export function logout() { 
        
  return request({ 
        
    url: '/admin/acl/index/logout',
    method: 'post'
  })
}
  1. axios二次封装:axios所在位置是utils/requerst.js中,由于原文件使用的是mock数据,返回的code如果成功的话是20000,但是如果是真实的接口,返回正确的code应该是200,因此修改代码。
 if (res.code !== 20000 && res.code !== 200)

4.换成真实接口之后需要解决代理跨域问题:webpack涉及的知识,可以去webpack官网-配置-devServer-devServer.proxy中寻找

   // vue.config.js
   // 配置代理跨域
   proxy: { 
        
     '/dev-api': { 
        
       target: 'http://39.98.123.211',
       pathRewrite: { 
         '^/dev-api': '' }
     }
   }

四、退出登录业务

  1. 静态页面的更改:layout中包含系统的框架,比如菜单栏等,其中Navbar.vue中有退出等按钮,修改即可。

  2. 同时也要修改路由为真实路由。


五、项目路由的搭建

  1. 删除views中不需要的组件,只留下dashboard和login,同时删除相关路由。

  2. 创建project文件夹,里面存放管理系统需要的功能(tradeMark,Attr,Sku,Spu),分别创建vue文件。

  3. 模仿其他路由的书写方式,编写router中的index.js路由部分

{ 
        
  path: '/product',
  component: Layout,
  name: 'Product',
  meta: { 
        
    title:'商品管理',icon:'el-icon-goods'
  },
  children: [
    { 
        
      path: 'trademark',
      name: 'Trademark',
      component: () => import('@/views/product/tradeMark'),
      meta: { 
        title:'品牌管理'}
    },
    { 
        
      path: 'attr',
      name: 'Attr',
      component: () => import('@/views/product/Attr'),
      meta: { 
        title:'品牌属性'}
    },
    { 
        
      path: 'sku',
      name: 'Sku',
      component: () => import('@/views/product/Sku'),
      meta: { 
        title:'Sku管理'}
    },
    { 
        
      path: 'spu',
      name: 'Spu',
      component: () => import('@/views/product/Spu'),
      meta: { 
        title:'Spu管理'}
    }
  ]
}
  1. 一个小错误:styles/index.scss中最后的一个类名写错了,导致一个布局不能实现,应为
.app-main { 
        
padding: 20px;
}

六、完成品牌管理(tradeMark)静态组件

  1. 首先有一个添加按钮,并有一个加号图标
<!-- 按钮 -->
<el-button type="primary" icon="el-icon-plus" style="margin: 10px 0">添加</el-button>
  1. 表格组件,表格中的数据的行数可以根据提供数组的长度来自动调整,因此我们只需要控制列数,有几列便有几个el-table-column。
<el-table style="width: 100%" border>
 <el-table-column prop="prop" label="序号" width="80px" align="center" type="index">
 </el-table-column>
 <el-table-column prop="prop" label="品牌名称" width="width">
 </el-table-column>
 <el-table-column prop="prop" label="品牌LOGO" width="width">
 </el-table-column>
 <el-table-column prop="prop" label="操作" width="width">
 </el-table-column>
</el-table>
  • border:添加边框 ----整个表格是有边框的

  • label:显示的标题 ----每一列的表头是什么

  • width:对应列的宽度 ----第一列的宽度不一样,width的就是均分

  • align:对齐方式 左 中 右 ----序号列是居中对齐

  1. 分页器,之前封装过分页器,element-ui中也有封装好的分页器
<el-pagination
style="margin-top:20px;text-align:center"
  :current-page="1"
  :page-sizes="[3, 5, 10]"
  :page-size="3"
  :pager-count="7"
  layout="prev, pager, next, jumper,->,sizes,total"
  :total="99"
  @current-change="getPageList"
  @size-change="handleSizeChange"
  >
</el-pagination>
  • current-page当前第几页

  • total总页数

  • page-size每页数据数

  • page-sizes每页数据数备选

  • layout布局位置 — ->是居右

  • pager-count页面有的页码数,连续页码数为pager-count - 2 个


七、完成品牌管理列表的展示

  1. 数据获取,首先书写获取数据的请求,在线文档中有API.

    • 在api中创建product存放product相关请求(attr.js sku.js spu.js tradeMark.js).
// api/tradeMark.js中
import request from '@/utils/request'
export const reqTradeMarkList = (page, limit) => request({ 
         url: `/admin/product/baseTrademark/${ 
          page}/${ 
          limit}`, method: 'get' });
  • 为了方便其他API的引入,可以把API挂载在原型上,就可以通过this.直接引入了。
// main.js中
// 引入相关API请求接口
import API from '@/api'
//将API挂载在原型上
// 任何组件可以使用API相关接口
Vue.prototype.$API = API
  • 由于这个接口需要两个参数,分别是page 和 limit,因此现在data中给出两个参数,以及给出一个数组,用于接收得到的数据。total是分析返回数据结构后也需要接收的。
data() { 
        
  return { 
        
    page:1,
    limit:3,
    total:0,
    list:[]
  }
  • 数据获取
mounted(){ 
        
  this.getPageList()
},
methods:{ 
        
  async getPageList(pager = 1){ 
        
    this.page = pager
    //解构参数
    const { 
        page,limit} = this
    let result =  await this.$API.trademark.reqTradeMarkList(page,limit)
    if(result.code == 200){ 
        
      this.total = result.data.total
      this.list = result.data.records
    }
  },
}
  1. 数据展示

    • 数组的数据在el-table中用data表示,每一列的数据用el-table-column中的prop表示。

    • 如果表格中含有图片、按钮等其他结构,需要使用定义域插槽。定义域插槽的理解:数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定

<el-table style="width: 100%" border :data="this.list">
  <el-table-column prop="prop" label="序号" width="80px" align="center" type="index">
  </el-table-column>
  <el-table-column prop="tmName" label="品牌名称" width="width">
  </el-table-column>
  <el-table-column prop="prop" label="品牌LOGO" width="width">
    <template slot-scope="{row,$index}">
      <img :src="row.logoUrl" alt="" style="width:100px;height:100px">
    </template>
  </el-table-column>
  <el-table-column prop="prop" label="操作" width="width">
    <template slot-scope="{row,$index}">
      <el-button icon="el-icon-edit" type="warning" size="mini">修改</el-button>
      <el-button icon="el-icon-delete" type="danger" size="mini">删除</el-button>
    </template>
  </el-table-column>
</el-table>
  • 作用域插槽中的row表示el-table中含有的数据,已经按照行分配好的。
  1. 分页器点击的实现

    • 分页器还包括两个事件

      @current-change=“handleCurrentChange” ----点击页码的时候触发,会携带着点击的页码paper,可以和数据加载放在一起写,因为更换页码后也要重新请求。

      @size-change=“handleSizeChange” ----修改每页展示的数目,会携带这改变后的个数。

    • 分页器相关代码

<el-pagination style="margin-top:20px;text-align:center" :current-page="page" :page-sizes="[3, 5, 10]" :page-size="3" :pager-count="7" layout="prev, pager, next, jumper,->,sizes,total" :total="total" @current-change="getPageList" @size-change="handleSizeChange" >
  
methods:{
  async getPageList(pager = 1){
    this.page = pager
    //解构参数
    const {page,limit} = this
    let result =  await this.$API.trademark.reqTradeMarkList(page,limit)
    if(result.code == 200){
      this.total = result.data.total
      this.list = result.data.records
    }
  },
  // 当分页器某一页需要展示数据条数发生变化时会触发
  handleSizeChange(limit){
    this.limit = limit
    this.getPageList()
  }
}

八、添加品牌与修改品牌的静态组件

  1. 点击添加或者修改会弹出相同的遮罩层,element-ui中有这个组件。图片上传也有相应的组件。

  2. 相关代码

<el-dialog title="添加品牌" :visible.sync="dialogFormVisible">
  <el-form style="width: 80%" :model="tmForm">
    <el-form-item label="品牌名称" label-width="100px">
      <el-input autocomplete="off" v-model="tmForm.tmName"></el-input>
    </el-form-item>
    <el-form-item label="品牌LOGO" label-width="100px">
      <el-upload class="avatar-uploader" action="dev-api/admin/product/fileUpload" :show-file-list="false" :on-success="handleAvatarSuccess" :before-upload="beforeAvatarUpload" >
        <img v-if="tmForm.logoUrl" :src="tmForm.logoUrl" class="avatar" />
        <i v-else class="el-icon-plus avatar-uploader-icon"></i>
        <div slot="tip" class="el-upload__tip">
          只能上传jpg/png文件,且不超过500kb
        </div>
      </el-upload>
    </el-form-item>
  </el-form>
  <div slot="footer" class="dialog-footer">
    <el-button @click="dialogFormVisible = false">取 消</el-button>
    <el-button type="primary" @click="addOrUpdateTradeMark">确 定</el-button>
  </div>
</el-dialog>

九、完成添加品牌功能

  1. 添加品牌有自己的接口,且添加品牌和修改品牌的操作非常相似,区别就是修改品牌会返回id,因此,在API书写的时候,将添加品牌和修改品牌封装成一个请求。
export const reqAddOrUpdateTradeMark = (tradeMark) => { 
         
    if (tradeMark.id) { 
        
        //修改品牌
        return request({ 
         url: '/admin/product/baseTrademark/update', method: 'put', data: tradeMark })
    } else { 
         
        // 新增品牌
        return request({ 
         url: '/admin/product/baseTrademark/save', method: 'post', data: tradeMark })
    }
}
  1. 为了对应请求参数,创建一个数据tmForm,包含logoUrl和tmName,用于参数传递。
data() { 
        
  return { 
        
    tmForm: { 
        
      logoUrl: "",
      tmName: "",
    },
  };
},
  1. 添加品牌请求携带的参数是品牌名称和品牌图片,因此首先要收集到弹出框的信息,element-ui中用于收集表单元素的标签是 :model,可以告诉表单把数据收集到哪个元素身上。文字的收集采用v-model,图片的收集要使用action,可以设置图片的上传的地址。el-upload标签还有两个事件,:on-success:可以监测图片上次成功,会执行一次,:before-upload 可以在上传图片之前,会执行一次。

  2. 图片上传成功之前,要对图片进行格式大小判断,上传之后,要将图片url传递给tmForm中的logoUrl,展示的图片也要变成logoUrl。(见八的相关代码)

  3. 点击确认以后,首先隐藏弹出框,然后待着参数发请求,并弹出结果,重新获取数据。

// 点击添加
showDialog() { 
        
  this.dialogFormVisible = true;
  // 每次点击添加之前都要清空数据,避免残留
  this.tmForm.logoUrl = ""
  this.tmForm.tmName = ""
},
//图片上传成功
handleAvatarSuccess(res, file) { 
        
  this.tmForm.logoUrl = res.data;
},
//图片上传之前
beforeAvatarUpload(file) { 
        
  const isJPG = file.type === "image/jpeg";
  const isLt2M = file.size / 1024 / 1024 < 2;

  if (!isJPG) { 
        
    this.$message.error
        标签: p150光电传感器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台