0


① 尚品汇的后台管理系统【尚硅谷】【Vue】

后台管理系统项目简介

  1. 什么是后台管理系统项目?在前端领域当中,开发后台管理系统项目,并非是Java,PHP等后台语言项目在前面课程当中,我们已经开发了一个项目【尚品汇电商平台项目】,这个项目主要针对的是用户(游客),可以让用户在平台当中购买产品。但是你需要想明白一件事情,用户购买产品信息从何而来呀?比如:前台项目当中的数据来源于卖家(公司),但是需要注意的时候,卖家它不会数据库操作。对于卖家而言,需要把产品的信息上传于服务器,写入数据库。卖家并非程序员,不会数据库操作(增删改查)。导致卖家,找了一个程序员,开发一个产品,可以让我进行可视化操作数据库(增删改查)卖家(公司)组成:老板、员工。 老板:开发这个项目,对于老板而言,什么都可以操作。【产品的上架、产品的下架、查看员工的个人业绩、其他等等】 员工:可能就是查看个人业绩
  2. 后台管理系统:可以让用户通过一个可视化工具,可以实现对于数据库进行增删改查的操作。 而且需要注意,根据不同的角色(老板、员工),看到的、操作内容是不同的。对于后台管理系统项目,一般而言,是不需要注册的。

模板介绍

简洁版: https://github.com/PanJiaChen/vue-admin-template 我们用这个
加强版: https://github.com/PanJiaChen/vue-element-admin

  1. 解压后发现文件夹里没有node_modules文件夹,我们需要安装依赖npm install
  2. 然后我们运行一下---->去看他的package.json文件下"dev": "vue-cli-service serve",说明我们用dev来运行npm run dev

运行界面如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8oJaUwIW-1661958702221)(后台项目笔记.assets/image-20220820120405960.png)]

模板的文件与文件夹认知【简洁版】

build
----index.js 是webpack配置文件【很少修改这个文件】
mock
----mock数据的文件夹【模拟一些假的数据mockjs实现的】,因为咱们实际开发的时候,利用的是真是接口

node_modules
------项目依赖的模块

public
------ico图标,静态页面,public文件夹里面经常放置一些静态资源,而且在项目打包的时候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:项目配置项文件
.env.development:开发环境的配置文件
.env.producation:生产环境的配置文件

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

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

最新后台文档swagger地址:
http://39.98.123.211:8510/swagger-ui.html#/

完成登录业务

  1. 静态组件完成
  2. 书写API(换成真实的接口)
  3. axios二次封装
  4. 换成真实接口之后需要解决代理跨域问题(解决代理跨域问题)

在这里插入图片描述

完成静态组件

修改里面的样式以及内容

这里修改了背景图片,以及把英文的都换成了中文

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Fy0kcq2B-1661958802101)(后台项目笔记.assets/image-20220820132621069.png)]

⚠️这里引入背景图片可以用

@

符号,但是前面要加

~

另外把背景图片的大小调整为 100% 100%

.login-container{min-height: 100%;width: 100%;background:url(~@/assets/城堡.jpg);background-size: 100% 100%;overflow: hidden;

书写API(换成真实的接口)

这里之前登录的使用模拟的数据(mock),我们换成真实的接口

Swagger UI这里找接口

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T99AvEBN-1661958802102)(后台项目笔记.assets/image-20220820180632745.png)]

url改为接口里的url

//   src/api/user.js// 对外暴露登录的接口函数exportfunctionlogin(data){returnrequest({url:'dev-api/admin/acl/index/login',method:'post',
    data
  })}// 对外暴露获取用户信息的接口函数exportfunctiongetInfo(token){returnrequest({url:'dev-api/admin/acl/index/info',method:'get',params:{ token }})}// 对外暴露退出登录的接口函数exportfunctionlogout(){returnrequest({url:'dev-api/admin/acl/index/logout',method:'post'})}

axios二次封装修改

这里我们的请求头携带的token字段

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V4XnjNoX-1661958802103)(后台项目笔记.assets/image-20220820140645142.png)]

响应拦截器

我们换成了真实的接口,真实服务器返回的code ,有可能是20000,也有可能是200

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UmtVlMvj-1661958802103)(后台项目笔记.assets/image-20220820140738001.png)]

解决代理跨域问题

开发中 Server(devServer) | webpack 中文网 (webpackjs.com)代理跨域

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UMXPgxiq-1661958802105)(后台项目笔记.assets/image-20220820141402508.png)]

我们有两个端口号,一个是8170,一个是8510,所以我们可以设置多个代理跨域

我们这里的传递的是

/dev-api

dev-list

,target地址也要修改

//    vue.config.js//  配置代理跨域proxy:{// 关于用户的接口"/dev-api":{target:"http://39.98.123.211:8170",pathRewrite:{"^/dev-api":""}},// 关于品牌的接口"/dev-list":{target:"http://39.98.123.211:8510",pathRewrite:{"^/dev-list":""}},}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9ClgQlh7-1661958802105)(后台项目笔记.assets/image-20220821180531730.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-55ZSS3u0-1661958802106)(后台项目笔记.assets/image-20220821180454986.png)]

⚠️修改完配置项,要重新启动项目

完成退出登录业务

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q7eXMu7A-1661959005362)(后台项目笔记.assets/image-20220820181255174.png)]

完成静态组件

修改退出登录的样式和结构,将英文修改成中文的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JwphDfwZ-1661959005363)(后台项目笔记.assets/image-20220820181749381.png)]

书写API(换成真实的接口)

//   src/api/user.js// 对外暴露退出登录的接口函数exportfunctionlogout(){returnrequest({url:'/admin/acl/index/logout',method:'post'})}

路由的搭建

我们只需要首页,删掉其余不需要的路由文件夹,然后重新配置路由

我们的一级路由都是在Layout这个骨架下搭建的,所以一级路由的componen都写Layout

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CtgNbThJ-1661959005363)(后台项目笔记.assets/image-20220820190328274.png)]

首页(一级路由)

权限管理(一级路由)

商品管理(一级路由)

​ -------品牌管理(二级路由)

​ ---- --平台属性管理(二级路由)

​ -------Spu管理(二级路由)

​ -------Sku管理(二级路由)

// src/router/index.js{// 一级路由path:'/product',component:Layout,// 在Layout的骨架下!!name:'Product',meta:{title:'商品管理',icon:'el-icon-goods'},// // title是设置侧边栏的文字children:[// 二级路由{path:'trademark',name:'TradeMark',component:()=>import('@/views/product/tradeMark'),meta:{title:'品牌管理'},},{path:'attr',name:'Attr',component:()=>import('@/views/product/Attr'),meta:{title:'平台属性管理'},},{path:'spu',name:'Spu',component:()=>import('@/views/product/Spu'),meta:{title:'Spu管理'},},{path:'sku',name:'Sku',component:()=>import('@/views/product/Sku'),meta:{title:'Sku管理'},},],},

搭建后的:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8tTTO7LL-1661959005364)(后台项目笔记.assets/image-20220820190407716.png)]

另外,我们的内容 AppMain 需要与左侧有个内边距,我们去加个

padding:20px

完成品牌管理业务tradeMark❓

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aqeBjiA7-1661959231339)(后台项目笔记.assets/image-20220823222646898.png)]

完成静态组件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mLy2w5FD-1661959231341)(后台项目笔记.assets/image-20220821115300881.png)]

  1. 添加button按钮// src/views/product/tradeMark/index.vue<!-- 按钮 --><el-button type="primary" icon="el-icon-plus" style="margin:10px 0">添加</el-button>
  2. 添加table表格—显示的标题要居中—且序号的占比要小> > el-table> > 属性:> > ​ data:表格组件将来需要展示的数据【数组类型】> > ​ border:是给表格带上边框> > > > el-table-column> > 属性:> > ​ label:显示的标题> > ​ width:对应列的宽度> > ​ align:对齐方式 <!-- 表格组件 --> <el-table border> <el-table-column label="序号" width="80" align="center"></el-table-column> <el-table-column label="品牌类型" align="center"></el-table-column> <el-table-column label="品牌LOGO" align="center"></el-table-column> <el-table-column label="操作" align="center"></el-table-column> </el-table>
  3. 分页器----要居中> > el-pagination> > 的属性:> > ​ current-page:当前第几页> > ​ page-size:每一页展示多少数据> > ​ layout:实现分页器顺序布局 > > ->> > 后面的数据在最右面> > ​ total:数据总条数 <!-- 分页器 --> <!--@size-change="handleSizeChange" @current-change="handleCurrentChange" --> <el-pagination :current-page="6" :page-sizes="[3, 5, 10]" :page-size="3" layout=" prev, pager, next, jumper,->,sizes, total" :total="90" style="margin-top:20px;text-align:center" > </el-pagination>

品牌列表展示❓

  1. 书写相关API接口
  2. 获取数据进行存储

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-56klL4IA-1661959231341)(后台项目笔记.assets/image-20220821132345452.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0C8wptV1-1661959231343)(后台项目笔记.assets/image-20220821132550742.png)]

获取分页列表数据 /admin/product/baseTrademark/{page}/{limit} GET 带参数

书写相关API接口

//  src/api/product/tradeMark.js// 品牌管理的相关接口// 我们发请求需要用的是封装好的axiosimport request from'@/utils/request'// 获取品牌分页列表数据    dev-api/admin/product/baseTrademark/{page}/{limit}      GET    exportconstreqTradeMarkList=(page, limit)=>{returnrequest({url:`dev-list/admin/product/baseTrademark/${page}/${limit}`,method:'GET'})}

为方便使用,将四个模块的接口函数统一对外暴露

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3KLuNwst-1661959231343)(后台项目笔记.assets/image-20220821201432876.png)]

为了方便,可以任意使用接口函数,可以在入口函数中,将接口挂载在原型上

//   src/main.js// 引入相关API请求接口---挂载在原型上importAPIfrom'@/api/index'// 组件实例的原型的原型指向的是Vue.prototype// 任意组件可以使用API相关的接口Vue.prototype.$API=API;

获取数据

我们挂载的时候需要获取数据,点击xx页的时候也要获取数据,所以我们将获取数据写在方法里面

<script>
export default {
  name: "tradeMark",
  data() {
    return {
      page: 2, // 代表分页器当前第几页
      limit: 3, // 当前页数展示的多少条数据
      total:0, // 总共数据的条数
      list:[], // 列表里面要展示的数据
    };
  },
  mounted() {
    // 获取列表数据的方法
    this.getPageList();
  },
  methods: {
    // 获取品牌列表的数据
    async getPageList() {
      // 解构出参数
      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;
      }
    },
  },
};
</script>

👇已经得到的数据,接下来开始展示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6sRAuiB1-1661959231344)(后台项目笔记.assets/image-20220821202419854.png)]

展示数据❓

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aXTZIuNa-1661959231345)(后台项目笔记.assets/image-20220821215815123.png)]

  1. elementUI当中的table组件,展示的数据是以一列一列进行展示数据的
  2. 如果需要显示索引,可以增加一列el-table-column,设置type属性为index即可显示从 1 开始的索引号。
  3. prop:对应列内容的字段名,也可以使用 property 属性【字符串类型】

el-tabel

:data="list"

表示这个表格展示的是哪里面的数据

第一列 我们要展示的是序列号,可以用

 type="index"

表示从1 开始展示索引号

第二列 我们展示的是品牌类型,在list 里面的tmName,我们可以用

prop

:对应列内容的字段名

    <el-table border :data="list">
        
      <el-table-column
        label="序号"
        width="80"
        align="center"
        type="index"
      ></el-table-column>
        
      <el-table-column label="品牌类型" prop="tmName"></el-table-column>
        
      <el-table-column label="品牌LOGO">
        <!-- { row, $index }是固定的名字,不能瞎写 -->
        <template slot-scope="{ row, $index }">
          <!-- row代表的是数组回传的数据 -->
          <img :src="row.logoUrl" alt="" style="width: 100px; height: 100px" />
        </template>
      </el-table-column>
        
      <el-table-column label="操作">
        <template slot-scope="{ row, $index }">
          <el-button type="warning" icon="el-icon-edit>" size="mini"
            >修改</el-button
          >
          <el-button type="danger" icon="el-icon-delete>" size="mini"
            >删除</el-button
          >
        </template>
      </el-table-column>
        
    </el-table>

第三列 展示的是品牌logo,是个图片,我们有地址,我们可以用【作用域插槽】来展示图片

slot-scope="{ row, $index }"

代表的是子组件回传过来的数据,也就是

list

​ 然后我们进行动态展示图片

:src

❓第四列 有两个按钮,为什么要用作用域插槽??????

👇分页器渲染数据

    <el-pagination
      :current-page="page"
      :page-sizes="[3, 5, 10]"
      :page-size="limit"
      layout=" prev, pager, next, jumper,->,sizes, total"
      :total="total"
      style="margin-top: 20px; text-align: center"
      :page-count="7"
    >
    </el-pagination>

完成相关点击事件

当点击页数的时候,修改data里面的page,然后再次发请求

@current-change="handleCurrentChange"

当你点击其他页数时触发

    <el-pagination
      :current-page="page"
      :page-sizes="[3, 5, 10]"
      :page-size="limit"
      layout=" prev, pager, next, jumper,->,sizes, total"
      :total="total"
      style="margin-top: 20px; text-align: center"
      :page-count="7"
      @current-change="handleCurrentChange"
      @size-change="handleSizeChange"
    >
    </el-pagination>
// 点击页码进行切换handleCurrentChange(pager){// pager你点击的页数// 修改参数,然后再发请求this.page = pager ;this.getPageList();},
@size-change="handleSizeChange"

当pageSize【展示数据条数】改变时触发

// 当分页器某一页需要展示数据的条数发生变化时触发handleSizeChange(limit){// 修改数据,再次发请求this.limit = limit ;this.getPageList();},

完成添加品牌与修改品牌业务

当你点击品牌管理页面 左上角【添加】的时候,会弹出一个类似遮罩层的页面

当你点击【修改】,也会弹出一个类似遮罩层的页面-----------显示对话框

完成静态页面

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NeKj1d7D-1661959231347)(后台项目笔记.assets/image-20220822195730896.png)]

  1. 我们这里用elementui的 dialog 对话框[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LNuPwNAl-1661959231347)(后台项目笔记.assets/image-20220822193245571.png)] <!-- 对话框 --> <!-- :visible.sync:控制对话框的显示与隐藏 --> <el-dialog :title="tmForm.id ? '修改品牌' : '添加品牌'" :visible.sync="dialogFormVisible"> <!-- 展示表单元素form --> <el-form style="width: 80%"> <!-- 第一行:品牌名称 --> <el-form-item label="品牌名称" label-width="100px"> <el-input autocomplete="off"></el-input> </el-form-item> <!-- 第二行:品牌LOGO --> <el-form-item label="品牌LOGO" label-width="100px"> <!--上传图片的位置--> </el-form-item> </el-form> <!-- 对话框底部的取消与确定 --> <div slot="footer" class="dialog-footer"> <el-button @click="dialogFormVisible = false">取 消</el-button> <el-button type="primary" @click="dialogFormVisible = false">确 定</el-button> </div> </el-dialog>
  2. 上传图片用elementui的Upload上传[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GUmeYxzE-1661959231348)(后台项目笔记.assets/image-20220822194522686.png)]
 <el-upload
            class="avatar-uploader"
            action="https://xxxxxxxxxx"
            :show-file-list="false"
            :on-success="handleAvatarSuccess"
            :before-upload="beforeAvatarUpload"
          >
            <img v-if="imageUrl" :src="imageUrl" 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>
  1. 粘贴elementui里面相关的数据和方法与样式data(){return{dialogFormVisible:false,// 对话框显示与隐藏的控制属性imageUrl:"",// 上传图片使用的属性}},methods:{// 上传图片相关的回调handleAvatarSuccess(res, file){this.imageUrl =URL.createObjectURL(file.raw);},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;},}

完成 添加品牌 的功能

当点击【添加品牌】按钮

  1. 收集相应【品牌名称和LOGO】
  2. 将收集到的发请求提交给后台
  3. 然后再发请求获取品牌列表数据

书写相关的API接口

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rYQ6XoIQ-1661959231349)(后台项目笔记.assets/image-20220822212013946.png)]

新增品牌 /admin/product/baseTrademark/save POST 带参数

// 处理 添加品牌的 操作 /admin/product/baseTrademark/save    POST  带参数 品牌名称和品牌logo// 切记:对于新增的品牌,给服务器传递参数,不需要传递ID,ID是由服务器生成exportconstreqAddTradeMark=(tradeMark)=>{returnrequest({url:'dev-list/admin/product/baseTrademark/save',method:'POST',data:tradeMark})}

收集数据并发请求

  1. 收集到表单元素里的数据> 要收集到elementui里面的表单数据,就要在该表单上面添加 > > model> > 属性,将来表单验证也需要这个属性 <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>> 收集LOGO图片> > 这里收集数据不能使用v-model,因为不是表单元素,我们这里用了另一个> > el-upload> > > > action:设置图片上传的地址> > on-success 可以检测到图片上传成功,图片上传成功会执行一次> > before-upload :可以在上传图片之前,会执行一次 <el-upload class="avatar-uploader" action="/dev-list/admin/product/upload" :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>``````// 点击【添加品牌】的按钮showDialog(){// 显示对话框this.dialogFormVisible =true;// 先清除之前的数据this.tmForm ={tmName:'',logoUrl:''}},// 图片上传成功handleAvatarSuccess(res, file){// res是你上传成功后服务器返回你的数据,里面是图片在服务器的真实地址// file :上传成功后服务器返回的前端数据// 收集上传图片数据this.tmForm.logoUrl = res.data;},
  2. 发请求> 当点击【添加品牌】里的【确定】按钮时> > > 1. 将弹出的对话框隐藏> 2. 发请求(添加品牌> 3. 如果成功,弹出一个message框:可能是添加成功,也有可能是修改成功,然后重新获取新的品牌列表<el-button type="primary" @click="addOrUpdateTradeMark">确 定</el-button>``````// 点击【添加按钮】里面的【确定按钮】(可以添加品牌|修改品牌)asyncaddOrUpdateTradeMark(){// 将弹出的对话框隐藏this.dialogFormVisible =false;// 发请求(添加品牌 | 修改品牌)let result =awaitthis.$API.trademark.reqAddTradeMark(this.tmForm);if(result.code ==200){// 弹出一个message框:可能是添加成功,也有可能是修改成功this.$message(this.tmForm.id ?"修改品牌成功":"添加品牌成功");// 获取新的品牌列表this.getPageList();}},

完成 修改品牌 的功能❓

书写相关的API

修改 品牌的操作 /admin/product/baseTrademark/update PUT 带参数 ID和品牌名称和品牌logo

// 修改 品牌的操作  /admin/product/baseTrademark/update  PUT   带参数   ID和品牌名称和品牌logo// 切记:对于修改某一个品牌的参数,前端携带的参数需要带上id,你需要告诉服务器修改的是哪一个品牌exportconstreqUpdateTradeMark=(tradeMark)=>{returnrequest({url:'dev-list/admin/product/baseTrademark/update',method:'PUT',data:tradeMark})}

收集数据并发请求❓

  1. 当你点击【修改】按钮时,会弹出一个对话框,里面默认显示你点这个品牌的信息所以我们点击【修改】按钮时,会把row这一品牌的信息传过去,这里用到了作用域插槽
    <el-table-column label="操作">
        <!-- row代表的是这一品牌的信息 -->
        <template slot-scope="{ row, $index }">
          <el-button
            type="warning"
            icon="el-icon-edit>"
            size="mini"
            @click="updateTrademark(row)"
            >修改</el-button>
          <el-button type="danger" icon="el-icon-delete>" size="mini">删除</el-button>
        </template>
    </el-table-column>

​ tmForm 是我们收集的弹出框的表单数据,并非我们要展示的列表数据,我们要用tmFrom当我们的参数去发请求

​ list 是我们要展示的列表数据

​ ❓为什么要用浅拷贝 tmForm????

(这里不用浅拷贝的话,当你在弹出框更改品牌名称的时候,品牌列表展示页面会自动的更新你修改的数据—无论你点了【取消】还是【确定修改】)

// 点击【修改某一个品牌】按钮updateTrademark(row){// row 是当前用户选中的这个品牌的信息,服务器返回给我们的// 显示对话框this.dialogFormVisible =true;// 将已有的品牌信息赋值给tmForm进行展示// 将服务器返回的品牌信息,直接赋值给了tmForm进行展示// tmForm存储的就是服务器返回的品牌信息this.tmForm ={...row};},
  1. 当你修改完成后,点击【确定】按钮,发请求去修改品牌,请求成功后再发请求获取品牌列表进行展示 1. 将弹出的对话框隐藏2. 判断是【添加】还是【修改】 看是否tmForm.id3. 是修改的就发修改的请求,是添加的就发添加的请求4. 请求成功后,弹出一个message框:可能是添加成功,也有可能是修改成功5. 再次获取新的品牌列表
// 点击【添加按钮】里面的【确定按钮】(可以添加品牌|修改品牌)asyncaddOrUpdateTradeMark(){// 1. 将弹出的对话框隐藏this.dialogFormVisible =false;// 2. 判断是【添加】还是【修改】 看是否tmForm.idlet result =null;if(this.tmForm.id){// 是修改
        result =awaitthis.$API.trademark.reqUpdateTradeMark(this.tmForm);}else{// 发请求(添加品牌 | 修改品牌)
        result =awaitthis.$API.trademark.reqAddTradeMark(this.tmForm);}if(result.code ==200){// 3. 弹出一个message框:可能是添加成功,也有可能是修改成功this.$message({type:'success',message:this.tmForm.id ?"修改品牌成功":"添加品牌成功",});// 4. 获取新的品牌列表this.getPageList();}},

表单验证功能

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tcbCBtMB-1661959231349)(后台项目笔记.assets/image-20220823183317539.png)]


Form 组件提供了表单验证的功能,只需要通过

rules

属性传入约定的验证规则,并将 Form-Item 的

prop

属性设置为需校验的字段名即可。校验规则参见 async-validator

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WnQ307fj-1661959231350)(后台项目笔记.assets/image-20220823205617407.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bvjfHdYr-1661959546370)(后台项目笔记.assets/image-20220823205856445.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lMQJJ7VA-1661959231351)(后台项目笔记.assets/image-20220823205856445.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sjimYwpC-1661959231351)(后台项目笔记.assets/image-20220823210033272.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q2L3BeLK-1661959231352)(后台项目笔记.assets/image-20220823210204260.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hrfLCn6t-1661959231353)(后台项目笔记.assets/image-20220823210409973.png)]

最重要的是自定义校验规则!!!form表单校验–Vue UI 框架 (eleme.cn)

完整代码

<template>
  <div>
    <!-- 按钮 -->
    <el-button
      type="primary"
      icon="el-icon-plus"
      style="margin: 10px 0"
      @click="showDialog"
      >添加</el-button
    >
    <!-- 表格组件 -->
    <!-- data:表格组件将来需要展示的数据【数组类型】
        border:是给表格带上边框
        el-table-column:label【显示的标题】 width【对应列的宽度】align【对齐方式】
        注意1:elementUI当中的table组件,展示的数据是以一列一列进行展示数据的
        如果需要显示索引,可以增加一列el-table-column,设置type属性为index即可显示从 1 开始的索引号。
        prop:对应列内容的字段名,也可以使用 property 属性【字符串类型】
     -->
    <el-table border :data="list">
      <el-table-column
        label="序号"
        width="80"
        align="center"
        type="index"
      ></el-table-column>

      <el-table-column label="品牌类型" prop="tmName"></el-table-column>

      <el-table-column label="品牌LOGO">
        <!-- { row, $index }是固定的名字,不能瞎写 -->
        <template slot-scope="{ row, $index }">
          <!-- row代表的是数组回传的数据,logoUrl是服务器返回的数据 -->
          <img :src="row.logoUrl" style="width: 100px; height: 100px" />
        </template>
      </el-table-column>

      <el-table-column label="操作">
        <!-- row代表的是这一品牌的信息 -->
        <template slot-scope="{ row, $index }">
          <el-button
            type="warning"
            icon="el-icon-edit>"
            size="mini"
            @click="updateTrademark(row)"
            >修改</el-button
          >
          <el-button type="danger" icon="el-icon-delete>" size="mini"
            >删除</el-button
          >
        </template>
      </el-table-column>
    </el-table>

    <!-- 分页器 -->
    <!-- 当前第几页[current-page],
          数据总条数[total],
          每一页数据展示多少[page-size],
          连续页码数
          layout:实现分页器布局
          pager-count:按钮的数量,如果是9,那么连续页码是7
           -->
    <el-pagination
      :current-page="page"
      :page-sizes="[3, 5, 10]"
      :page-size="limit"
      layout=" prev, pager, next, jumper,->,sizes, total"
      :total="total"
      style="margin-top: 20px; text-align: center"
      :page-count="7"
      @current-change="handleCurrentChange"
      @size-change="handleSizeChange"
    >
    </el-pagination>

    <!-- 弹出的对话框 -->
    <!-- :visible.sync:控制对话框的显示与隐藏 -->
    <el-dialog
      :title="tmForm.id ? '修改品牌' : '添加品牌'"
      :visible.sync="dialogFormVisible"
    >
      <!-- 展示表单元素form -->
      <!-- :model 收集到的表单数据 ,将来表单验证也需要这个属性,tmForm将数据保存到这里-->
      <!-- Form 组件提供了表单验证的功能,只需要通过`rules` 属性传入约定的验证规则,并将 Form-Item 的 `prop`属性设置为需校验的字段名即可。 -->
      <el-form style="width: 80%" :model="tmForm" :rules="rules" ref="ruleForm">
        <!-- 第一行:品牌名称 -->
        <el-form-item label="品牌名称" label-width="100px" prop="tmName">
          <el-input autocomplete="off" v-model="tmForm.tmName"></el-input>
        </el-form-item>

        <!-- 第二行:品牌LOGO -->
        <el-form-item label="品牌LOGO" label-width="100px" prop="logoUrl">
          <!-- 这里收集数据不能使用v-model,因为不是表单元素 -->
          <!-- action:设置图片上传的地址 -->
          <!-- on-success 可以检测到图片上传成功,图片上传成功会执行一次 -->
          <!-- before-upload :可以在上传图片之前,会执行一次 -->
          <el-upload
            class="avatar-uploader"
            action="/dev-list/admin/product/upload"
            :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文件,且不超过2MB
            </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>
  </div>
</template>

<script>
export default {
  name: "tradeMark",
  data() {
    return {
      page: 2, // 代表分页器当前第几页
      limit: 3, // 当前页数展示的多少条数据
      total: 0, // 总共数据的条数
      list: [], // 列表里面要展示的数据
      dialogFormVisible: false, // 对话框显示与隐藏的控制属性
      tmForm: {
        // 收集的品牌信息,对象身上的属性不能瞎写,需要看文档
        tmName: "",
        logoUrl: "",
      },
      // 表单验证的规则
      rules: {
        // 品牌名称的验证规则
        tmName: [
          // required:必须要检验的字段,是否带*号
          // message:提示的信息
          // trigger:用户行为设置(事件的设置blur失焦,change变化)
          { required: true, message: "请输入品牌名称", trigger: "blur" },
          {
            min: 2, // 品牌名称的长度
            max: 10,
            message: "长度在 2 到 10 个字符",
            trigger: "change", // 文本发生变化就触发
          },
        ],
        // 品牌logo的验证规则
        logoUrl: [{ required: true, message: "请选择品牌的图片" }],
      },
    };
  },
  mounted() {
    // 获取列表数据的方法
    this.getPageList();
  },
  methods: {
    // 获取品牌列表的数据
    async getPageList() {
      // 解构出参数
      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;
      }
    },
    // 点击页码进行切换
    handleCurrentChange(pager) {
      // pager你点击的页数
      // 修改参数,然后再发请求
      this.page = pager;
      this.getPageList();
    },
    // 当分页器某一页需要展示数据的条数发生变化时触发
    handleSizeChange(limit) {
      // 修改数据,再次发请求
      this.limit = limit;
      this.getPageList();
    },
    // 点击【添加品牌】的按钮
    showDialog() {
      // 显示对话框
      this.dialogFormVisible = true;
      // 清除数据
      this.tmForm = { tmName: "", logoUrl: "" };
    },
    // 点击【修改某一个品牌】按钮
    updateTrademark(row) {
      // row 是当前用户选中的这个品牌的信息,服务器返回给我们的
      // 显示对话框
      this.dialogFormVisible = true;
      // 将已有的品牌信息赋值给tmForm进行展示
      // 将服务器返回的品牌信息,直接赋值给了tmForm进行展示
      // tmForm存储的就是服务器返回的品牌信息
      this.tmForm = { ...row };
    },
    // 图片上传成功
    handleAvatarSuccess(res, file) {
      // 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("上传头像图片只能是 JPG 格式!");
      }
      if (!isLt2M) {
        this.$message.error("上传头像图片大小不能超过 2MB!");
      }
      return isJPG && isLt2M;
    },
    // 点击【添加按钮】里面的【确定按钮】(可以添加品牌|修改品牌)
    addOrUpdateTradeMark() {
      // 当全部验证的字段通过,再去书写业务逻辑
      this.$refs.ruleForm.validate(async (success) => {
        // 如果全部字段符合条件
        if (success) {
          // 1. 将弹出的对话框隐藏
          this.dialogFormVisible = false;
          // 2. 判断是【添加】还是【修改】 看是否tmForm.id
          let result = null;
          if (this.tmForm.id) {
            // 是修改
            result = await this.$API.trademark.reqUpdateTradeMark(this.tmForm);
          } else {
            // 3. 发请求(添加品牌 | 修改品牌)
            result = await this.$API.trademark.reqAddTradeMark(this.tmForm);
          }

          if (result.code == 200) {
            // 4. 弹出一个message框:可能是添加成功,也有可能是修改成功
            this.$message({
              type: "success",
              message: this.tmForm.id ? "修改品牌成功" : "添加品牌成功",
            });
            // 获取新的品牌列表
            this.getPageList();
          }
        } else {
          console.log("提交错误");
          return false;
        }
      });
    },
  },
};
</script>

完成删除品牌业务

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2Z3RwJQ7-1661959761320)(后台项目笔记.assets/image-20220823222607114.png)]

当点击【删除】按钮时,会弹出一个弹框【确定要删除吗】,然后有【确定】和【取消】两个按钮

  1. 点击【删除】按钮,给【删除】绑定点击事件deleteTradeMark,要传参数(你点击该品牌的信息—row)
  2. 弹出一个弹框,里面是【确定删除】还是【取消】
  3. 确定后,发请求删除该品牌,然后再发请求获取品牌列表数据;

书写相关API

删除该品牌 /admin/product/baseTrademark/remove/{id} DELETE 带参数

// 删除该品牌  /admin/product/baseTrademark/remove/{id}   DELETE  带参数exportconstreqDeleteTradeMark=(id)=>{returnrequest({url:`dev-list/admin/product/baseTrademark/remove/${id}`,method:'DELETE'})}

发请求完成删除功能

  1. 弹窗[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hieEbiMG-1661959761321)(后台项目笔记.assets/image-20220823214342223.png)]// 删除品牌的操作deleteTradeMark(row){// 弹窗this.$confirm(`你确定删除${row.tmName}吗?`,"提示",{confirmButtonText:"确定",cancelButtonText:"取消",type:"warning",}).then(()=>{// 当用户点击【确定】按钮的时候触发this.$message({type:"success",message:"删除成功!",});}).catch(()=>{// 当用户点击【取消】按钮的时候会触发this.$message({type:"info",message:"已取消删除",});});},
  2. 发请求----完成删除功能// 删除品牌的操作deleteTradeMark(row){// 弹窗this.$confirm(`你确定删除${row.tmName}吗?`,"提示",{confirmButtonText:"确定",cancelButtonText:"取消",type:"warning",}).then(async()=>{// 1. 当用户点击【确定】按钮的时候触发// 2. 向服务器发请求let result =awaitthis.$API.trademark.reqDeleteTradeMark(row.id);if(result.code ==200){// 3. 弹出message框this.$message({type:"success",message:"删除成功!",});// 4. 再次获取品牌列表数据this.getPageList();}}).catch(()=>{// 当用户点击【取消】按钮的时候会触发this.$message({type:"info",message:"已取消删除",});});},

完成平台属性管理业务attr

应该会跳转到下一文章👉


本文转载自: https://blog.csdn.net/muziqwyk/article/details/126634208
版权归原作者 不爱吃菜的蔡菜 所有, 如有侵权,请联系我们删除。

“① 尚品汇的后台管理系统【尚硅谷】【Vue】”的评论:

还没有评论