vue后台(二)

 

一,添加品牌的表单验证

前台表单校验(内置规则和自定义规则)
    如果不加校验,那么没有图片也会上传过去

    使用element-ui的form
        品牌名称:
            1、必须有   输入过程中校验
            2、长度        失去焦点校验
        品牌logo
            必须有      点击确认按钮去校验
            
        校验时机:三种

        参考官方文档

    我们的代码点击确定要先去整体校验校验  参考文档  修改代码    

 

1.通过element官网的form表单验证规则,单一验证,在el-form中定义rules属性,然后在data中定义rules, 然后在el-form-item中配置prop属性

 <el-form :model="form" style="width:80%" :rules="rules" ref="form">
        <el-form-item label="品牌名称" :label-width="formLabelWidth" prop="tmName">
          <el-input v-model="form.tmName" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="品牌LOGO" :label-width="formLabelWidth" prop="logoUrl">
          <el-upload
            class="avatar-uploader"
            action="/dev-api/admin/product/fileUpload"
            :show-file-list="false"
            :on-success="handleLogoSuccess"
            :before-upload="beforeLogoUpload"
          >
            <!-- 上传图片的接口地址,需要通过转发去到真实的接口地址 -->

            <img v-if="form.logoUrl" :src="form.logoUrl" class="avatar" />
            <i v-else class="el-icon-plus avatar-uploader-icon"></i>
            <div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
          </el-upload>
        </el-form-item>
      </el-form>

2,在data中定义rules

2.1,对象形式,tmName为输入框的输入数据的验证规则

2.2, message: 对表单验证的提示

2.3, trigger,通过哪些事件触发验证,blur为失去焦点判断,change,输入框数据改变时验证

2.4,图片change事件完成,上传成功后,不会有提示验证,但是在点击弹框的确定按钮,会有整体验证,此时会有提示

 
 rules: {
        tmName: [
          { required: true, message: "请输入品牌名称", trigger: "blur" },
          // {
          //   min: 2,
          //   max: 10,
          //   message: "长度在 2 到 10 个字符",
          //   trigger: "change",
          // },
          { validator: this.validateTmName, trigger: "change" },
        ],
        logoUrl: [
          { required: true, message: "请选择上传图片", trigger: "change" },
        ],
      },

 

3,点击弹框的确定按钮,需要整体验证,此时需要在<el-form 中配置ref属性

<el-form :model="form" style="width:80%" :rules="rules" ref="form">
        <el-form-item label="品牌名称" :label-width="formLabelWidth" prop="tmName">
 <div slot="footer" class="dialog-footer">
        <el-button @click="isShowDialog = false">取 消</el-button>
        <el-button type="primary" @click="addOrupdateTrademark">确 定</el-button>
      </div>
    </el-dialog>
    addOrupdateTrademark() {
      //整体添加验证规则
      this.$refs.form.validate(async (valid) => {
        //valid,整体表单项验证成功,才可以发送请求
        if (valid) {
          //添加和修改二合一
          //找参数
          let trademark = this.form;
          //发请求
          const result = await this.$API.trademark.addOrUpdate(trademark);
          //成功干啥
          if (result.code === 200) {
            this.$message.success(`${trademark.id ? "修改" : "添加"}品牌成功`);
            this.getTrademarkList(trademark.id ? this.page : 1); //重新加载数据 默认添加的新的品牌在最后
            this.isShowDialog = false;
          } else {
            //失败干啥
            this.$message.error(`${trademark.id ? "修改" : "添加"}品牌失败`);
          }
        } else {
          console.log("验证失败");
          return false;
        }
      });

      // //添加和修改二合一
      // //找参数
      // let trademark = this.form;
      // //发请求
      // const result = await this.$API.trademark.addOrUpdate(trademark);
      // //成功干啥
      // if (result.code === 200) {
      //   this.$message.success(`${trademark.id ? "修改" : "添加"}品牌成功`);
      //   this.getTrademarkList(trademark.id ? this.page : 1); //重新加载数据 默认添加的新的品牌在最后
      //   this.isShowDialog = false;
      // } else {
      //   //失败干啥
      //   this.$message.error(`${trademark.id ? "修改" : "添加"}品牌失败`);
      // }
    },

 

3.1,此时上传图片的change事件触发后,并不会有验证规则,只有点击弹框的确定按钮,才会验证

 

 

 

4.自定义规则,去官网查找, 对输入框输入数据的长度自定义规则,this.validateTmName为定义的一个函数,需要在methods中定义

 
 rules: {
        tmName: [
          { required: true, message: "请输入品牌名称", trigger: "blur" },
          // {
          //   min: 2,
          //   max: 10,
          //   message: "长度在 2 到 10 个字符",
          //   trigger: "change",
          // },
          { validator: this.validateTmName, trigger: "change" },
        ],
        logoUrl: [
          { required: true, message: "请选择上传图片", trigger: "change" },
        ],
      },

 

  methods: {
    //value为输入的字符串
    validateTmName(rule, value, callback){
      if (value.length < 2 || value.length > 10) {
        // callback 这个函数调用带了error错误信息,代表不通过
        callback(new Error("请输入2-10个字符"));
      } else {
        // callback 这个函数如果不带任何参数信息,代表验证过
        callback();
      }
    },

 

商品属性接口函数

商品属性(平台属性)相关的接口函数,并且导入到整体的index.js并导出让后面的组件当中可以导入使用
    内部更新和添加使用的是同一个,一个参数需要id 一个不需要
    在组件当中去测试一个

在api新建atrr文件夹(index.js)

import request from '@/utils/request'

const api_name = '/admin/product'

export default {
  /*
  获取属性列表
  GET /admin/product/attrInfoList/{category1Id}/{category2Id}/{category3Id
  */
  getList(category1Id,category2Id,category3Id) {
    return request({
      url: `${api_name}/attrInfoList/${category1Id}/${category2Id}/${category3Id}`,
      method: 'get',
    })
  },

  /*
  增加或者修改属性
  POST /admin/product/saveAttrInfo
  增加和修改一体  增加没id 修改有id
  */ 
  addOrUpdate(attr){
    return request({
      url:`${api_name}/saveAttrInfo`,
      method:'post',
      data:attr
    })
  },
  /*
  DELETE /admin/product/deleteAttr/{attrId}
  */
  delete(attrId){
    return request({
      url:`${api_name}/deleteAttr/${attrId}`,
      method:'delete'
    })
  }
  
}

 

在api新建文件夹category,搞三级列表接口函数

import request from '@/utils/request'

export default {

  /* 
  查找一级分类列表
  */
  getCategorys1() {
    return request({
      url: '/admin/product/getCategory1',
      method: 'get'
    })
  },

  /* 
  查找二级分类列表
  */
  getCategorys2(category1Id) {
    return request({
      url: '/admin/product/getCategory2/' + category1Id,
      method: 'get'
    })
  },

  /* 
  查找三级分类列表
  */
  getCategorys3(category2Id) {
    return request({
      url: '/admin/product/getCategory3/' + category2Id,
      method: 'get'
    })
  }
}

在api总的入口引入接口模块

export {default as attr} from './attr'
export {default as category} from './category'
 
 
二,平台属性管理功能静态页面搭建

 

 

1.顶部三级分类联动单独搞成组件CategorySelector, 然后在attr组件引入
全局该组件CategorySelector
// 引入准备全局注册的组件
import HintButton from '@/components/HintButton'
import CategorySelector from '@/components/CategorySelector'

// 注册全局组件
Vue.component('HintButton', HintButton)
Vue.component('CategorySelector', CategorySelector)

在attr中引入,外头包含一个el-card组件,忽悠立体浮动效果

<template>
  <div>
    <el-card>
      <CategorySelector @handlerCategory="handlerCategory"></CategorySelector>
    </el-card>

 

静态页面搭建

:model="cForm" 收集三个id的对象,是因为要通过id发送请求,请求数据,在data中定义

:inline="true" 表单是行内样式

label="区域一" 为下拉框的数据
<template>
    <el-form :inline="true" :model="cForm" class="demo-form-inline">
    <el-form-item label="一级分类">
      <el-select v-model="cForm.category1Id" placeholder="选择一级分类">
        <el-option
          label="区域一"
          value="上海"

        ></el-option>
      </el-select>
    </el-form-item>
    <el-form-item label="二级分类">
      <el-select v-model="cForm.category2Id" placeholder="选择二级分类">
        <el-option
           label="区域一"
          value="上海"
          
        ></el-option>
         <el-option
           label="区域二"
          value="北京"
          
        ></el-option>
      </el-select>
    </el-form-item>
    <el-form-item label="三级分类">
      <el-select v-model="cForm.category3Id" placeholder="选择三级分类">
        <el-option
           label="区域二"
          value="北京"
        ></el-option>
      </el-select>
    </el-form-item>
  </el-form>
</template>

<script>
export default {
  name: "CategorySelector",
  data(){
    return {
      //为了收集选中的类别id
      cForm: {
        category1Id: "",
        category2Id: "",
        category3Id: "",
      },
    }
  }

};
</script>

 

 

 

2,三级分类的组件动态显示数据  ,点击一级分类的数据(change事件),发送请求,获取分类列表的数据,就会决定二级分类展示什么数据,三级分类的数据也是如此

2.1,获取分类列表的响应数据,是个数组

{
  "code": 0,
  "data": [
    {
      "id": 0,
      "name": "string"
    }
  ],
  "message": "string",
  "ok": true
}

2.2, 在data中定义配置三级分类列表的响应数据

 //为了存储请求回来的数据
      category1List: [],
      category2List: [],
      category3List: [],

2.3, 在CategorySelector组件中加载的时候,就需要获取一级分类列表的数据,需要发送请求获取

  mounted() {
    this.getCategory1List();
  },
  methods: {
    //获取一级分类列表
    async getCategory1List() {
      const result = await this.$API.category.getCategorys1();
      if (result.code === 200) {
        this.category1List = result.data;
      }
    },

2.4在html模板中填充数据

 <el-form :inline="true" :model="cForm" class="demo-form-inline">
    <el-form-item label="一级分类">
      <el-select v-model="cForm.category1Id" placeholder="选择一级分类" @change="handlerC1">
        <el-option
          :label="c1.name"
          :value="c1.id"
          v-for="(c1, index) in category1List"
          :key="c1.id"
        ></el-option>
      </el-select>
    </el-form-item>

 

 

 

3,选中一级分类的时候触发获取二级分类列表,在<el-select绑定@change事件,默认传递的是选中值,也就是id值

 

 

 <el-form-item label="一级分类">
      <el-select v-model="cForm.category1Id" placeholder="选择一级分类" @change="handlerC1">
        <el-option

js代码,绑定该事件后,发送请求,获取二级分类列表数据

 // 选中一级分类的时候触发获取二级分类列表
    // @change="handlerC1",实参为默认选中的值
    async handlerC1(category1Id) {
     

      const result = await this.$API.category.getCategorys2(category1Id);
      if (result.code === 200) {
        this.category2List = result.data;
      }
    },

在模板中填充数据

   <el-form-item label="二级分类">
      <el-select v-model="cForm.category2Id" placeholder="选择二级分类" @change="handlerC2">
        <el-option
          :label="c2.name"
          :value="c2.id"
          v-for="(c2, index) in category2List"
          :key="c2.id"
        ></el-option>
      </el-select>
    </el-form-item>

 

 

4,选二级分类的时候触发获取三级分类列表,在<el-select绑定@change事件,默认传递的是选中值,也就是id值
 <el-form-item label="三级分类">
      <el-select v-model="cForm.category3Id" placeholder="选择三级分类" @change="handlerC3">
        <el-option
          :label="c3.name"
          :value="c3.id"
          v-for="(c3, index) in category3List"
          :key="c3.id"
        ></el-option>
      </el-select>
    </el-form-item>

js代码,绑定该事件后,发送请求,获取三级分类列表数据

// 选中二级分类的时候触发获取三级分类列表
    async handlerC2(category2Id) {
      
      const result = await this.$API.category.getCategorys3(category2Id);
      if (result.code === 200) {
        this.category3List = result.data;
      }
    },

 

5,此时有个bug,重新选择一级分类的数据,二级分类的数据没有变化,重新选择二级分类的数据,三级分类的数据没有变化,我们需要一选中一级分类的数据,二级,三级的id清空,并且

他们的数组分类数据也要清空, 一选中二级分类的数据,三级的id清空,并且三级数组分类数据也要清空

// 选中一级分类的时候触发获取二级分类列表
    // @change="handlerC1",实参为默认选中的值
    async handlerC1(category1Id) {
      //选中1级分类 把23级分类相关的都清空
      this.cForm.category2Id = "";
      this.cForm.category3Id = "";
      this.category2List = [];
      this.category3List = [];

      //向父传递选中的1级分类id
      this.$emit("handlerCategory", { categoryId: category1Id, level: 1 });

      const result = await this.$API.category.getCategorys2(category1Id);
      if (result.code === 200) {
        this.category2List = result.data;
      }
    },
 // 选中二级分类的时候触发获取三级分类列表
    async handlerC2(category2Id) {
      //选中2级分类 把3级分类相关的都清空
      this.cForm.category3Id = "";
      this.category3List = [];

      this.$emit("handlerCategory", { categoryId: category2Id, level: 2 });

      const result = await this.$API.category.getCategorys3(category2Id);
      if (result.code === 200) {
        this.category3List = result.data;
      }
    },

 

6,三级分类列表选择通知父组件发请求获取attr组件的属性数据

 获取属性列表
  GET /admin/product/attrInfoList/{category1Id}/{category2Id}/{category3Id
  */
  getList(category1Id,category2Id,category3Id) {
    return request({
      url: `${api_name}/attrInfoList/${category1Id}/${category2Id}/${category3Id}`,
      method: 'get',
    })
  },

 

6.1,每次选择1,2,3级分类的数据,需要传递id给父组件attr, 因为父组件需要接受三个id作为请求参数,发送请求,获取属性数据。而且是父组件获取到三级id时,正好可以发送请求,获取数据,子组件对id做个标识,区分id是哪级分裂的id

attr组件通过自定义函数和父子通信

  // 选中一级分类的时候触发获取二级分类列表
    // @change="handlerC1",实参为默认选中的值
    async handlerC1(category1Id) {
      //选中1级分类 把23级分类相关的都清空
      this.cForm.category2Id = "";
      this.cForm.category3Id = "";
      this.category2List = [];
      this.category3List = [];

      //向父传递选中的1级分类id
      this.$emit("handlerCategory", { categoryId: category1Id, level: 1 });

      const result = await this.$API.category.getCategorys2(category1Id);
      if (result.code === 200) {
        this.category2List = result.data;
      }
    },

 

 // 选中二级分类的时候触发获取三级分类列表
    async handlerC2(category2Id) {
      //选中2级分类 把3级分类相关的都清空
      this.cForm.category3Id = "";
      this.category3List = [];

      this.$emit("handlerCategory", { categoryId: category2Id, level: 2 });

      const result = await this.$API.category.getCategorys3(category2Id);
      if (result.code === 200) {
        this.category3List = result.data;
      }
    },

此时三级列表选中数据后,向父组件传递id

 <el-form-item label="三级分类">
      <el-select v-model="cForm.category3Id" placeholder="选择三级分类" @change="handlerC3">
        <el-option
   },
    // 选中三级分类的时候触发,给父传递选中的3级id
    handlerC3(category3Id) {
      this.$emit("handlerCategory", { categoryId: category3Id, level: 3 });
    },

6.2, attr父组件通过自定义函数和父子通信

<el-card>
      <CategorySelector @handlerCategory="handlerCategory"></CategorySelector>
    </el-card>

js代码

注,当获取到了三级id,此时发送请求获取最佳

如果用户重新选中三级列表的数据,传递过来了id,那么之前的id需要清空,之前获取的数组attrList数据也要清空

handlerCategory({ categoryId, level }) {
      // console.log(categoryId,level)
      if (level === 1) {
        //清空之前保留的2级级3级id以及之前请求的attrList
        this.category2Id = "";
        this.category3Id = "";
        this.attrList = [];

        this.category1Id = categoryId;
      } else if (level === 2) {
        this.category3Id = "";
        this.attrList = [];
        this.category2Id = categoryId;
      } else {
        this.category3Id = categoryId;
        //如果选中了三级,父组件会接收到3级id,代表要发请求,拿属性列表数据
        //三级被传过来,证明12级已经被传过来存储了
        //此时请求最佳
        this.getAttrList();
      }
    },

 

    async getAttrList() {
      let { category1Id, category2Id, category3Id } = this;
      const result = await this.$API.attr.getList(
        category1Id,
        category2Id,
        category3Id
      );
      if (result.code === 200) {
        this.attrList = result.data;
      }
    },
 data() {
    return {
      //获取数据所需的参数
      category1Id: "",
      category2Id: "",
      category3Id: "",
      attrList: [],

获取的响应数据

{
  "code": 200,
  "message": "成功",
  "data": [
    {
      "id": 1971,
      "attrName": "系统",
      "categoryId": 61,
      "categoryLevel": 3,
      "attrValueList": [
        {
          "id": 9922,
          "valueName": "ios",
          "attrId": 1971
        },
        {
          "id": 9921,
          "valueName": "塞班",
          "attrId": 1971
        },
        {
          "id": 9923,
          "valueName": "安卓",
          "attrId": 1971
        }
      ]
    },
    {
      "id": 1993,
      "attrName": "内存",
      "categoryId": 61,
      "categoryLevel": 3,
      "attrValueList": [
        {
          "id": 9911,
          "valueName": "32G",
          "attrId": 1993
        },
        {
          "id": 9908,
          "valueName": "8G",
          "attrId": 1993
        },
        {
          "id": 9910,
          "valueName": "16G",
          "attrId": 1993
        },
        {
          "id": 9907,
          "valueName": "4G",
          "attrId": 1993
        },
        {
          "id": 9909,
          "valueName": "12G",
          "attrId": 1993
        }
      ]
    },
   

 

7.atrr组件属性列表页的静态页面以及动态数据展示

注;添加属性按钮默认开始就是不可点击的,只要子组件传递过来的三级id,添加属性按钮才可以点击

el-tag,里头是双重遍历

<template>
  <div>
    <el-card>
      <CategorySelector @handlerCategory="handlerCategory"></CategorySelector>
    </el-card>

    <el-card >
    
        <el-button
          type="primary"
          icon="el-icon-plus"
          :disabled="!category3Id"
          
        >添加属性</el-button>
        <el-table :data="attrList" border style="width: 100%; margin-top:20px">
          <el-table-column align="center" type="index" label="序号" width="80"></el-table-column>
          <el-table-column prop="attrName" label="属性名称" width="150"></el-table-column>
          <el-table-column label="属性值列表" width="width">
            <template slot-scope="{row,$index}">
              <el-tag
                type="success"
                v-for="(attrValue, index) in row.attrValueList"
                :key="attrValue.id"
              >{{attrValue.valueName}}</el-tag>
            </template>
          </el-table-column>
          <el-table-column label="操作" width="150">
            <template slot-scope="{row,$index}">
              <el-button type="warning" icon="el-icon-edit" size="mini" title="修改"></el-button>
              <el-button type="danger" icon="el-icon-delete" size="mini" title="删除"></el-button>

            </template>
          </el-table-column>
        </el-table>
    
    </el-card>
    
  </div>
</template>

 

 

8,列表页和增加修改页的切换使用,没有用到路由,而是通过v-show实现,点击添加属性按钮触发

在data中定义isShowList:true,默认是展示列表页

 
<template>
  <div>
    <el-card>
      <CategorySelector @handlerCategory="handlerCategory"></CategorySelector>
    </el-card>

    <el-card >
    
      <div v-show="isShowList">
          <el-button
          type="primary"
          icon="el-icon-plus"
          :disabled="!category3Id"
          @click="showAddDiv"
        >添加属性</el-button>
        <el-table :data="attrList" border style="width: 100%; margin-top:20px">
          <el-table-column align="center" type="index" label="序号" width="80"></el-table-column>
          <el-table-column prop="attrName" label="属性名称" width="150"></el-table-column>
          <el-table-column label="属性值列表" width="width">
            <template slot-scope="{row,$index}">
              <el-tag
                type="success"
                v-for="(attrValue, index) in row.attrValueList"
                :key="attrValue.id"
              >{{attrValue.valueName}}</el-tag>
            </template>
          </el-table-column>
          <el-table-column label="操作" width="150">
            <template slot-scope="{row,$index}">
              <el-button type="warning" icon="el-icon-edit" size="mini" title="修改"></el-button>
              <el-button type="danger" icon="el-icon-delete" size="mini" title="删除"></el-button>

            </template>
          </el-table-column>
        </el-table>
      </div>

      <div v-show="!isShowList">
        添加修改页
      </div>
    
    </el-card>
    
  </div>
</template>

点击添加属性按钮,切换到添加修改页

showAddDiv(){
      this.isShowList=false
    }

 

9,添加品牌属性页html页通过接口文档,收集请求体参数,

 

 

 

接口文档的请求体参数

{
  "attrName": "string",
  "attrValueList": [
    {
      "attrId": 0,
      "id": 0,
      "valueName": "string"
    }
  ],
  "categoryId": 0,
  "categoryLevel": 0,
  "id": 0
}

 

9.1,在attr组件中的data中收集参数

 form: {
        attrName:'',
        attrValueList:[],
        categoryId: '',
        categoryLevel:3
      },

 

9.2,然后在设置静态页面

注;收集的form对象给el-form, 

 <div v-show="!isShowList">
        <el-form ref="form" :model="form" :inline="true">
          <el-form-item label="属性名">
            <el-input v-model="form.attrName" placeholder="请输入属性名"></el-input>
          </el-form-item>
        </el-form>

        <el-button type="primary" icon="el-icon-plus"  :disabled="!form.attrName" @click="addAttrValue">添加属性值</el-button>
        <el-button @click="isShowList = true">取消</el-button>

        <el-table
          border
          :data="form.attrValueList"
          style="width: 100%;margin:20px 0">
          <el-table-column
            align="center"
            type="index"
            label="序号"
            width="80">
          </el-table-column>
          <el-table-column
            prop="prop"
            label="属性值名称"
            width="width">
          <template slot-scope="{row,$index}">
              <el-input v-model="row.valueName" placeholder="请输入属性值名称" size="mini"></el-input>
            </template>

          </el-table-column>
          <el-table-column
            label="操作"
            width="width">
          </el-table-column>
        </el-table>
        <el-button type="primary">保存</el-button>
        <el-button @click="isShowList = true">取消</el-button>
      </div>

 

 

9.3,点击取消按钮,切换到商品属性展示页面,此时需要添加点击事件,对isShowList操作

添加属性值按钮,默认是置灰的,只要输入属性名,该按钮就不至灰,

  <el-button type="primary" icon="el-icon-plus"  :disabled="!form.attrName">添加属性值</el-button>

 

10,点击添加属性值按钮,向form对象中的attrValueList添加属性,row中暗含遍历
 <el-button type="primary" icon="el-icon-plus"  :disabled="!form.attrName" @click="addAttrValue">添加属性值</el-button>
 addAttrValue() {
      //点击添加属性值,需要给attrForm当中的attrValueList数组中塞一条数据,数据要参考接口文档
      //点击添加的这个属性值对象仅仅是为了让上面能出现一个输入框,此时这个属性值对象内部属性值都是空串和undefined

      // {
      // "attrId": 0,
      // "id": 0,
      // "valueName": "string"
      // }
      this.form.attrValueList.push({
        attrId: this.form.id, //添加属性可以添加属性值,但是添加属性的时候,这个新属性没有id
                                  //修改属性也可以添加属性值,那么修改的属性是有id的
        valueName: "",
      });
    },

此时这里有个bug,已经添加了属性值,返回到品牌属性展示页后,再次点击添加属性按钮,还是显示的是之前的属性的旧数据,此时必须在每次点击添加属性按钮时,清空form对象数据

 showAddDiv() {
       //清一下,为了把上次添加而取消的信息清理掉
      this.form = {
        attrName: "",
        attrValueList: [],
        categoryId: this.category3Id,
        categoryLevel: 3,
      },
      this.isShowList = false;
    },

 

 

 

 

posted @ 2020-08-29 09:08  全情海洋  阅读(274)  评论(0)    收藏  举报