商品分类页面

本秂侑毒 提交于 2020-01-15 07:17:18

把数据展示出来之后,发现时间栏目是时间戳,那么就要写一个全局的过滤器把时间戳转换成时间

/* 定义一个全局的把后台传过来的时间戳变成自定义事件样式的过滤器 */
Vue.filter('dateFormat', function (originVal) {

  const dt = new Date(originVal) //传入一个时间,然后把这个时间戳new成对象
  const y = dt.getFullYear() //获取年份
  const m = (dt.getMonth() + 1 + '').padStart(2, '0') //获取月份,由于月份是从0开始的 
  const d = (dt.getDate() + '').padStart(2, '0') //加一个空字符串是把当前得到的东西转换成字符串
  const hh = (dt.getHours() + '').padStart(2, '0')  //后面这个方法的作用就是如果不满两位数的话,就用0代替
  const mm = (dt.getMinutes() + '').padStart(2, '0')
  const ss = (dt.getSeconds() + '').padStart(2, '0')

  return `${y}-${m}-${d} ${hh}:${mm}:${ss}`
})

然后实现搜索框的搜索和清空功能

<el-col :span="6">
  <el-input placeholder="请输入内容" v-model="getTab.query" class="input-with-select" clearable @clear="getTable">
      <el-button slot="append" icon="el-icon-search" @click="getTable"></el-button>
  </el-input>
</el-col>
  /* 发送查询的字段 */
  getTab: {
    query: '',
    pagenum: 1,
    pagesize: 10
  },

首先绑定查询字段里的query,然后点击搜索就可以直接发送请求
然后清空,在使用clearable的时候,绑定一个@clear,然后发送查询请求就可以清空当前值然后在次发送请求。
然后高级一点的查询
在这里插入图片描述
用法
首先这里最外边的绑定查询字段的listQuery[searchType],根据下面的绑定的v-model=“searchType” 来选择[searchType]里面的值,然后然后选择这里listQuery[searchType]绑定的值是什么,然后输入的值就是listQuery[searchType]的值,然后通过这个值发送请求,就可以查到相应的东西。

  <el-col :span="6">
    <template>
      <el-input v-model="listQuery[searchType]" placeholder="请输入关键字" clearable class="input-with-select" style="width:400px;">
        <el-select slot="prepend" v-model="searchType" placeholder="请选择" style="width:100px;">
          <el-option label="姓名" value="per_name" />
          <el-option label="账号" value="userid" />
          <el-option label="邮箱" value="email" />
          <el-option label="电话" value="mobile" />
        </el-select>
      </el-input>
    </template>
  </el-col>

这里同理,通过修改查询里面的值来发送请求

  <el-col :span="3">
    <el-select v-model="rolesData" placeholder="请选择" @change="selectRoles">
      <el-option
        v-for="item in rolesOptions"
        :key="item.value"
        :label="item.label"
        :value="item.value"
      />
    </el-select>
  </el-col>

字段

  // 查询中第一个input框绑定的数据
  listQuery: {
    uni_id: '',
    per_name: '',
    userid: '',
    email: '',
    mobile: '',
    role: '',
    page: 1,
    pageSize: '20'
  },
  // 插槽下拉的选择的数据
  searchType: 'per_name',
  lists: [],
  list: null,
  page: 1,
  total: 0,
  loading: false,

然后展现出来后写添加商品,写个路由跳转

addGoods() {
  this.$router.push('/addgoods')
}

写另一个的路由和页面,然后设计
在这里插入图片描述
代码

  <div>
     <!-- 面包屑区域 -->
    <el-breadcrumb separator-class="el-icon-arrow-right">
      <el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
      <el-breadcrumb-item>商品管理</el-breadcrumb-item>
      <el-breadcrumb-item>添加商品</el-breadcrumb-item>
    </el-breadcrumb>
    <el-card>
      <!--  :closable="false" 表示可不可以删除这条警示框 -->
    <el-alert
    center
    title="添加商品信息"
    type="info"
    show-icon
    :closable="false"
    >
    </el-alert>
    <!-- finish-status表示已经完成的状态 active表示当前活跃的step,绑定的是序列号-->
    <el-steps :space="200" :active="activeIndex-0" finish-status="success" align-center>
      <el-step title="基本信息"></el-step>
      <el-step title="商品参数"></el-step>
      <el-step title="商品属性"></el-step>
      <el-step title="商品图片"></el-step>
      <el-step title="商品内容"></el-step>
      <el-step title="完成"></el-step>
    </el-steps>
    //这里利用这个from表单把这些东西包裹起来,把他们当成一个整体来后续操作 
    //label-position="top" 表示文字说明在输入框上面
    <el-form :model="addFromData"  label-position="top">
      <!--  绑定的是下面的name的值 ,表示当前在哪一个模块 -->
      <el-tabs v-model="activeIndex" tab-position="left" >
        <el-tab-pane label="基本信息" name="1">

          <el-form-item label="商品名称" prop="name">
            <el-input v-model="addFromData.goods_name"></el-input>
          </el-form-item>

          <el-form-item label="商品价格" prop="name">
            <el-input v-model="addFromData.goods_price"></el-input>
          </el-form-item>

          <el-form-item label="商品重量" prop="name">
            <el-input v-model="addFromData.goods_weight"></el-input>
          </el-form-item>

          <el-form-item label="商品数量" prop="name">
            <el-input v-model="addFromData.goods_number"></el-input>
          </el-form-item>

          <el-form-item label="商品分类">
            <el-cascader
              v-model="addFromData.goods_cat"
              :options="cate"
              :props="{
                value:'cat_id',
                label:'cat_name',
                children:'children'
              }"
              expand-trigger="hover"
              @change="handleChange"></el-cascader>
          </el-form-item>
        </el-tab-pane>
        <el-tab-pane label="商品参数" name="2">商品参数</el-tab-pane>
        <el-tab-pane label="商品属性" name="3">商品属性</el-tab-pane>
        <el-tab-pane label="商品图片" name="4">商品图片</el-tab-pane>
        <el-tab-pane label="商品内容" name="5">商品内容</el-tab-pane>
      </el-tabs>
    </el-form>
    </el-card>
  </div>

当写好了布局,现在就写限制商品tab页切换
使用的before-leave这个属性,绑定一个方法

   <!--  绑定的是下面的name的值 ,表示当前在哪一个模块 -->
      <el-tabs v-model="activeIndex" tab-position="left" :before-leave = "beforeTabLeare">
        <el-tab-pane label="基本信息" name="1">

方法里面传两个参数,分别是切换到的tab叫activeName 当前切换的叫oldactiveName
限制在第一个tab页面未选择商品分类时,不可以切换

beforeTabLeare(activeName, oldActiveName) {
  if (oldActiveName === '1' && this.addFromData.goods_cat !== 3) {
    this.$message.error('请选择商品分类')
    return false
  }
}

然后写切换到第二个tab,展现动态参数

 <!--  绑定的是下面的name的值 ,表示当前在哪一个模块 before-leave是绑定离开的tab和去到tab tab-click绑定当前去到哪一个tab-->
      <el-tabs v-model="activeIndex" tab-position="left" :before-leave = "beforeTabLeare" @tab-click="tabClick">
        <el-tab-pane label="基本信息" name="1">

然后
去到第二tab的时候,发送请求

  async tabClick() {
      if (this.activeIndex === '2') {
        const { data: res } = await this.$http.get(`categories/${this.getId}/attributes`, {
          params: { sel: 'many' }
        })
        if (res.meta.status !== 200) return
        this.cataParams = res.data
        //下面是把参数变成数组,给别人循环用
        this.cataParams.forEach(item => {
          item.attr_vals = item.attr_vals ? item.attr_vals.split(' ') : []
        })
      }
    }
  },
  computed: {
  //拿到第三级分类的id
    getId() {
      if (this.addFromData.goods_cat.length === 3) {
        return this.addFromData.goods_cat[2]
      }
      return null
    }
  }
}

然后
在这里插入图片描述
要展现这种风格

//这里绑定的是选定的;label值,也就是说一开始,,所有checkbox都是被选中的,如果取消选中,这个checkbox就会消失
<el-checkbox-group v-model="item.attr_vals">
 <el-checkbox :label="item2" v-for="(item2,i) in item.attr_vals" :key="i" border ></el-checkbox>
</el-checkbox-group>

然后由于排列不够整齐,可以这样,利用权重重新赋值

  .el-checkbox{
    margin: 0 5px 0 0 !important;
  }

然后拿静态属性,其实一样、

<el-tab-pane label="商品属性" name="3">
  <el-form-item :label="item.attr_name" v-for="item in this.onlyData" :key="item.attr_id">
    <el-input v-model="item.attr_vals" ></el-input>
  </el-form-item>
</el-tab-pane>
async tabClick() {
  if (this.activeIndex === '2') {
    const { data: res } = await this.$http.get(`categories/${this.getId}/attributes`, {
      params: { sel: 'many' }
    })
    if (res.meta.status !== 200) return
    this.cataParams = res.data
    this.cataParams.forEach(item => {
      item.attr_vals = item.attr_vals ? item.attr_vals.split(' ') : []
    })
  } else if (this.activeIndex === '3') {
    const { data: res } = await this.$http.get(`categories/${this.getId}/attributes`, {
      params: { sel: 'only' }
    })
    this.onlyData = res.data
    console.log(this.onlyData)
  }
}

然后下上传图片tab

<el-tab-pane label="商品图片" name="4">
  <!-- action表示图片要上传到的地址,on-preview 点击预览 ,on-remove点击删除 list-type这个图片上上传的ui类型 -->
  <el-upload
    class="upload-demo"
    :action="actionURL"
    :on-preview="handlePreview"
    :on-remove="handleRemove"
    list-type="picture">
    <el-button size="small" type="primary">点击上传</el-button>
    <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
  </el-upload>
</el-tab-pane>
  /* 上传到图片的位置 */
  actionURL: 'http://127.0.0.1:8888/api/private/v1/upload'

但是上面的上传不上经过axios的,所以他是不带token的,因为我们设定的是在使用axios发送请求的时候,拦截下来,设定token然后发送,所以现在要手动配置token

<!-- action表示图片要上传到的地址,on-preview 点击预览 ,on-remove点击删除 list-type这个图片上上传的ui类型 -->
          <el-upload
            :headers="headersObj"  //这里利用header属性绑定
            class="upload-demo"
            :action="actionURL"
            :on-preview="handlePreview"
            :on-remove="handleRemove"
            list-type="picture"
            :on-success="handleSuccess"  //这里设置一个上传成功后的钩子函数
            > 
            <el-button size="small" type="primary">点击上传</el-button>
            <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
          </el-upload>
  /* 手动配置taken */
  headersObj: {
    Authorization: window.sessionStorage.getItem('token')
      }

然后写配置上传成功后,把图片信息放到发送添加商品请求的字段那里
首先看文档要求
在这里插入图片描述
是这种样子,那么

    handleSuccess(respo) {
      /* 为了每上传一次就添加一张图片的临时路径,所以这里可以使用数组的push方法 */
      /* 因为上传一张图片,会为了创建一个临时对象来存储这个图片的信息,还是url路径,所以就要创建一个临时对象来保存上传上来的图片的图片信息,然后把对象push到相应的地方放 */
      /* 再看:pics":[{"pic":"/tmp_uploads/30f08d52c551ecb447277eae232304b8"}], 这是这个属性发送的请求方式,是使用一个pic存储路径的 */
      /* 所以首先通过拆创建一个对象来保存一个图片的图片信息对象 */
      console.log(respo)
      const picInfo = { pic: respo.data.tmp_path }
      /* 然后通过push,把图片对象弄进,再看:pics */
      this.addFromData.pics.push(picInfo)
      console.log(this.addFromData)
    }

然后查看请求参数
在这里插入图片描述
上传是这样的,那删除呢
删除绑定的这个方法,里面的第一个参数是当点击图片的删除按钮后,产生的钩子函数,这个file里面是这样的
在这里插入图片描述

/* 删除图片 */
handleRemove(file) {
  /* 删除图片首先是要获取到要删除图片的临时路径名字 */
  console.log(file)
  const filePath = file.response.data.tmp_path
  /* 然后通过这个临时路径找到他的索引值 */
  const i = this.addFromData.pics.findIndex(x => x.pic === filePath)
  /* 然后在pics数组中splice删掉就可以了 */
  this.addFromData.pics.splice(i, 1)
  console.log(this.addFromData)
},

预览图片
在方法 :on-preview="handlePreview"
首先拿一个对话框来保存展示图片,然后在对话框里面设置一个img

/* 预览图片 */
handlePreview(file) {
  /* 先拿到file的真实路径 */
  const fileUrl = file.response.data.url
  /* 然后把这个url放到要展示的img里 */
  this.Preview = fileUrl
  this.dialogVisible = true
},

现在写一个富文本编辑器
首先安装npm install vue-quill-editor --save
然后导入它还有一些css样式文件

/* 导入富文本编辑器 */
import VueQuillEditor from 'vue-quill-editor'

// require styles
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'

然后去到官方文档那里,然后使用的时候,只需要使用那个组件就可以了

 <quill-editor v-model="addFromData.goods_introduce" style="height:300px;"></quill-editor>

然后现在正式添加商品
在添加商品之前,由于发送请求的数据那里的goods.cat 是数组,但是文档要求是字符串,所以需要进行转换子啊发送过去,
但是 如果使用join把添加商品中的绑定分类的数组变成字符串,报错
所以,为了解决这个问题,现在使用深拷贝
首先安装,然后直接使用import导入

// 官方推荐使用下行线 _ 作为导入,就像jquery的 $ 符号一样
// eslint-disable-next-line no-unused-vars
import _ from 'lodash'

使用到的方法是cloneDeep方法

addGoods() {
  this.$refs.addFrom.validate(valid => {
    if (!valid) return
    /* 看文档,由于发送请求的字段里面要求商品分类使用的是字符串,但是级联选择器里面绑定必须是数组 */
    /* 如果使用join把添加商品中的绑定分类的数组变成字符串,报错 */
    /* 所以,为了解决这个问题,现在使用深拷贝 */

    const from = _.cloneDeep(this.addFromData)
    from.goods_cat = from.goods_cat.join(',')
    console.log(from)
  })
}

处理完这个,接下来就是处理动态,静态属性
在这里插入图片描述
首先看发送请求的字段可以看到,attrs数组里面放的是一个个对象,对象里面有参数,所以想法就是
在发送请求之前创建对象,对象里面就是attrs数组里面的对象的样子,然后把对象push到这个数组里面

addGoods() {
  this.$refs.addFrom.validate(async valid => {
    if (!valid) return
    /* 看文档,由于发送请求的字段里面要求商品分类使用的是字符串,但是级联选择器里面绑定必须是数组 */
    /* 如果使用join把添加商品中的绑定分类的数组变成字符串,报错 */
    /* 所以,为了解决这个问题,现在使用深拷贝 */
    const from = _.cloneDeep(this.addFromData)
    from.goods_cat = from.goods_cat.join(',')
    
    /* 处理动态参数 */
   //这里因为原本checkbox绑定的就是item.attr_vals,所以这个数组里本来就拥有全部,然后如果不选中的checkbox对应的attr_vals 就会从item.attr_vals 里面删除
    this.cataParams.forEach(item => {
      /* 从他们身上取出来这两个属性,然后把他们装进一个数组里面 */
      const newParams = { attr_id: item.attr_id, attr_vals: item.attr_vals.join(',') }
      from.attrs.push(newParams)
    })
    
    /* 处理静态属性 */
    this.onlyData.forEach(item => {
      const newParams = { attr_id: item.attr_id, attr_value: item.attr_vals }
      from.attrs.push(newParams)
    })
    
    /* 发送请求 */
    const { data: res } = await this.$http.post('goods', from)
    if (res.meta.status !== 201) {
      return
    }
    this.$message.success('成功')
    this.$router.push('/goods')
  })
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!