• Vue项目后台部分2,文件夹介绍,登录页面,路由的搭建,品牌管理页面使用element-ui动态展示


    文件夹介绍

    build----index.js: 是webpack配置文件
    mock:mock数据的文件夹【模拟一些假的数据】,实际开发利用的是真实的接口
    node_modules:项目依赖的模块
    public:ico图标,静态页面,该文件夹里面经常放置一些静态资源,而且在项目打包的时候webpack不会编译这个文件夹,原封不动的打包到dist文件夹里面
    src:
    ---- 程序员源代码的地方
    ---- api文件夹:涉及相关请求
    ---- assets文件夹:里面放置一些静态资源(一般是共享的),放在该文件夹里的静态资源,在webpack打包的时候,会进行编译
    ---- componets文件夹:一般放置非路由组件或是全局组件
    ---- icons文件夹放置一些svg矢量图
    ---- layout文件夹放置了组件和混入
    ---- router文件夹与路由相关
    ---- store文件夹与vux相关
    ---- style文件夹与样式相关的
    ---- utils文件夹:request.js是axios二次封装文件
    ---- views 文件夹:里面放置的路由组件
    App.vue:根组件
    main.js:入口文件
    permission.js:与导航守卫相关
    settings.js:项目的配置项文件

    登录页面

    1、静态组件完成,使用element-UI
    2、将假的接口换成真实的接口并且解决代理跨域问题,在vue.config.js文件里的devServer中配置如下

    //配置代理跨域
    proxy: {
      '/dev-api': {
        target: 'http://gmall-h5-api.atguigu.cn',
        pathRewrite: { '^/dev-api': '' }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    然后重启服务器
    3、action

      // 这里在处理登录业务
      async login({ commit }, userInfo) {
        // 解构出用户名与密码
        const { username, password } = userInfo
        let result = await login({ username: username.trim(), password: password });
        // 注意:当前登录请求现在使用mock数据,mock数据code是20000
        if (result.code == 20000) {
          // vuex存储token
          commit('SET_TOKEN', result.data.token)
          // 本地持久化存储token
          setToken(result.data.token)
          return 'ok'
        } else {
          return Promise.reject(new Error('faile'))
        }
      },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    4、绑定事件

    //登录业务:发请求,带着用户名与密码给服务器(成功与失败)
    handleLogin() {
      //这里是在验证表单元素(用户名与密码)的是否符合规则
      this.$refs.loginForm.validate(valid => {
        //如果符合验证规则
        if (valid) {
          //按钮会有一个loading效果
          this.loading = true;
          //派发一个action:user/login,带着用户名与密码的载荷
          this.$store.dispatch('user/login', this.loginForm).then(() => {
            //登录成功进行路由的跳转
            this.$router.push({ path: this.redirect || '/' });
            //loading效果结束
            this.loading = false
          }).catch(() => {
            this.loading = false
          })
        } else {
          console.log('error submit!!')
          return false
        }
      })
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    路由的搭建

    删掉不需要的路由组件,删除之后无法运行,因为这些路由已经被配置,所以需要删掉。
    新建自己需要的路由,然后搭建路由,使用路由懒加载引入组件。

    品牌管理

    动态展示

    1、静态组件,按钮和表格组件以及分页器

    
    <el-table style="width: 100%" border :data="list">
      <el-table-column label="序号" width="80px" align="center">
      el-table-column>
      <el-table-column label="品牌名称" width="width">
      el-table-column>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
        <!-- 
          分页器 
          当前第几页、数据总条数、每一页展示条数、连续页码数
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
    
          current-page:代表的是当前第几页
          total:代表分页器一共需要展示数据条数
          page-size:代表的是每一页需要展示多少条数据
          page-sizes:代表可以设置每一页展示多少条数据
          layout:可以实现分页器布局
          pager-count:按钮的数量  如果 9  连续页码是7
    
        -->
        <el-pagination
          style="margin-top: 20px; text-align: center"
          :current-page="page"
          :total="total"
          :page-size="limit"
          :pager-count="7"
          :page-sizes="[3, 5, 10]"
          @current-change="getPageList"
          @size-change="handleSizeChange"
          layout="prev, pager, next, jumper,->,sizes,total"
        >
      </el-pagination>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    2、接口
    3、写一个获取品牌列表数据的方法
    4、品牌管理列表的获取

    // 获取品牌列表的数据
    async getPageList(pager = 1) {
      this.page = pager;
      // 解构出参数
      const { page, limit } = this;
      // 获取品牌列表的接口
      // 当你向服务器发请求的时候,这个函数需要带参数,因此老师在data当中初始化两个字段,代表给服务器传递参数
      let result = await this.$API.trademark.reqTradeMarkList(page, limit);
      if (result.code == 200) {
        // 分别是展示数据总条数与列表展示的数据
        this.total = result.data.total;
        this.list = result.data.records;
      }
    },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    5、数据展示

    <el-table style="width: 100%" border :data="list">
      <el-table-column type="index" label="序号" width="80px" align="center">
      el-table-column>
      <el-table-column prop="tmName" label="品牌名称" width="width">
      el-table-column>
      <el-table-column prop="logoUrl" 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
            type="warning"
            icon="el-icon-edit"
            size="mini"
            @click="updateTradeMark(row)"
            >修改el-button
          >
          <el-button
            type="danger"
            icon="el-icon-delete"
            size="mini"
            @click="deleteTradeMark(row)"
            >删除el-button
          >
        template>
      el-table-column>
    el-table>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    6、分页器点击事件

    // 获取品牌列表的数据
    async getPageList(pager = 1) {
      this.page = pager;
      // 解构出参数
      const { page, limit } = this;
      // 获取品牌列表的接口
      // 当你向服务器发请求的时候,这个函数需要带参数,因此老师在data当中初始化两个字段,代表给服务器传递参数
      let result = await this.$API.trademark.reqTradeMarkList(page, limit);
      if (result.code == 200) {
        // 分别是展示数据总条数与列表展示的数据
        this.total = result.data.total;
        this.list = result.data.records;
      }
    },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    // 当分页器某一页需要展示数据条数发生变化的时候会触发
    handleSizeChange(limit) {
      // 整理参数
      this.limit = limit;
      this.getPageList();
    },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    添加品牌

    1、静态组件

    
    <el-dialog
      :title="tmForm.id ? '修改品牌' : '添加品牌'"
      :visible.sync="dialogFormVisible"
    >
      
      <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>
        <el-form-item label="品牌LOGO" label-width="100px" prop="logoUrl">
          
          <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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    2、点击事件显示对话框

        // 点击添加品牌的按钮
        showDialog() {
          // 显示对话框
          this.dialogFormVisible = true;
          // 清除数据
          this.tmForm = { tmName: "", logoUrl: "" };
        },
        // 修改某一个品牌
        updateTradeMark(row) {
          // row:当前用户选中这个品牌信息
          // 显示对话框
          this.dialogFormVisible = true;
          // 将已有的品牌信息赋值给tmForm进行展示
          // 将服务器返回品牌的信息,直接赋值给了tmForm进行展示。
          // 也就是tmForm存储即为服务器返回品牌信息
          this.tmForm = { ...row };
        },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    3、上传图片相关的回调

    // 图片上传成功
    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;
    },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    4、完成功能
    (1)接口
    (2)

    //处理添加品牌
    //新增品牌: /admin/product/baseTrademark/save   post  携带两个参数:品牌名称、品牌logo
    //切记:对于新增的品牌,给服务器传递数据,不需要传递ID,ID是由服务器生成
    
    //修改品牌的
    //修改品牌 /admin/product/baseTrademark/update   put   携带三个参数:id、品牌名称、品牌logo
    //切记:对于修改某一个品牌的操作,前端携带的参数需要带上id,你需要告诉服务器修改的是哪一个品牌
    
    export const reqAddOrUpdateTradeMark = (tradeMark) => {
        //带给服务器数据携带ID---修改
        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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    图片收集,action:设置图片上传的地址
    (3)功能实现

    // 添加按钮(添加品牌|修改品牌)
    addOrUpdateTradeMark() {
      // 当全部验证字段通过,再去书写业务逻辑
      this.$refs.ruleForm.validate(async (success) => {
        // 如果全部字段符合条件
        if (success) {
          this.dialogFormVisible = false;
          // 发请求(添加品牌|修改品牌)
          let result = await this.$API.trademark.reqAddOrUpdateTradeMark(
            this.tmForm
          );
          if (result.code == 200) {
            // 弹出信息:添加品牌成功、修改品牌成功
            this.$message({
              type: "success",
              message: this.tmForm.id ? "修改品牌成功" : "添加品牌成功",
            });
            // 添加或者修改品牌成功以后,需要再次获取品牌列表进行展示
            // 如果添加品牌: 停留在第一页,修改品牌应该留在当前页面
            this.getPageList(this.tmForm.id ? this.page : 1);
          }
        } else {
          console.log("error submit!!");
          return false;
        }
      });
    },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    // 修改某一个品牌
    updateTradeMark(row) {
      // row:当前用户选中这个品牌信息
      // 显示对话框
      this.dialogFormVisible = true;
      // 将已有的品牌信息赋值给tmForm进行展示
      // 将服务器返回品牌的信息,直接赋值给了tmForm进行展示。
      // 也就是tmForm存储即为服务器返回品牌信息
      this.tmForm = { ...row };
    },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    注意:
    由于tmFrom是直接影响列表展示的,而服务器收集数据也是用到的tmFrom,当修改品牌时,如果直接将row赋值给tmFrom,tmFrom会影响到服务器返回的值,即使点击取消,表单列表展示的数据也发生了改变,所以此时需要用到浅拷贝,即将服务器的数据拷贝一份赋值给tmFrom而不会影响到row。

    (4)表单验证功能

    // 自定义校验规则
    var validateTmName = (rule, value, callback) => {
      // 自定义校验规则
      if (value.length < 2 || value.length > 10) {
        callback(new Error("品牌名称2-10位"));
      } else {
        callback();
      }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
      // 表单验证规则
      rules: {
        // 品牌名称的验证规则
        // require:必须要校验字段(前面五角星有关系)  message 提示信息    trigger:用户行为设置(事件的设置:blur、change)
        tmName: [
          { required: true, message: "请输入品牌名称", trigger: "blur" },
          // 自定义校验规则
          { validator: validateTmName, trigger: "change" },
        ],
        // 品牌的logo验证规则
        logoUrl: [{ required: true, message: "请选择品牌的图片" }],
      },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    需要所有表单验证通过才可以发送请求

    删除品牌

    1、弹框设置

        // 删除品牌的操作
        deleteTradeMark(row) {
          // 弹框
          this.$confirm(`你确定删除${row.tmName}?`, "提示", {
            confirmButtonText: "确定",
            cancelButtonText: "取消",
            type: "warning",
          })
            .then(async () => {
              // 当用户点击确定按钮的时候会出发
              // 向服务器发请求
              let result = await this.$API.trademark.reqDeleteTradeMark(row.id);
              // 如果删除成功
              if (result.code == 200) {
                this.$message({
                  type: "success",
                  message: "删除成功!",
                });
                // 再次获取品牌列表数据
                this.getPageList(this.list.length > 1 ? this.page : this.page - 1);
              }
            })
            .catch(() => {
              // 当用户点击取消按钮的时候会触发
              this.$message({
                type: "info",
                message: "已取消删除",
              });
            });
        },
      },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    2、接口

    //删除品牌
    ///admin/product/baseTrademark/remove/{id}  delete
    
    export const reqDeleteTradeMark = (id)=>request({url:`/admin/product/baseTrademark/remove/${id}`,method:'delete'});
    
    • 1
    • 2
    • 3
    • 4

    3、当点击确认按钮,要向服务器发请求

    // 当用户点击确定按钮的时候会出发
    // 向服务器发请求
    let result = await this.$API.trademark.reqDeleteTradeMark(row.id);
    
    • 1
    • 2
    • 3
    // 再次获取品牌列表数据
    this.getPageList(this.list.length > 1 ? this.page : this.page - 1);
    
    • 1
    • 2
  • 相关阅读:
    2022-09-28 Android APP 用interface 接口的形式对jni进行回调,实例测试
    “薄利多销”策略研究与建模
    【华为OD机试真题 python】斗地主之顺子【2022 Q4 | 200分】
    痞子衡嵌入式:瑞萨RA8系列高性能MCU开发初体验
    自动化测试面试经历
    中间代码生成(Intermediate Code Generation)
    【深入浅出 Yarn 架构与实现】1-1 设计理念与基本架构
    Ai图像绘制模型训练以及应用
    核壳二氧化钛纳米颗粒修饰DNA|二氢杨梅素修饰DNA药物|相关介绍
    从阿里、头条面试回来,面试官最喜欢问的 Jvm 和 Redis 你了解多少?
  • 原文地址:https://blog.csdn.net/qq_49080239/article/details/126746500