硅谷甄选五(品牌管理)

一、静态组件

//src/views/product/trademark/index.vue
<template>
  <el-card class="box-card">
    <!-- 卡片顶部添加品牌按钮 -->
    <el-button type="primary" size="default" icon="Plus">添加品牌</el-button>
    <!-- 表格组件,用于展示已有的数据 -->
    <!-- 
      table
      ---border:是否有纵向的边框
      table-column
      ---lable:某一个列表
      ---width:设置这一列的宽度
      ---align:设置这一列对齐方式
     -->
    <el-table style="margin: 10px 0px" border>
      <el-table-column
        label="序号"
        width="80px"
        align="center"
      ></el-table-column>
      <el-table-column label="品牌名称"></el-table-column>
      <el-table-column label="品牌LOGO"></el-table-column>
      <el-table-column label="品牌操作"></el-table-column>
    </el-table>
    <!-- 分页器组件 -->
    <!-- 
      pagination
      ---v-model:current-page:设置当前分页器页码
      ---v-model:page-size:设置每一也展示数据条数
      ---page-sizes:每页显示个数选择器的选项设置
      ---background:背景颜色
      ---layout:分页器6个子组件布局的调整 "->"把后面的子组件顶到右侧
     -->
    <el-pagination
      v-model:current-page="pageNo"
      v-model:page-size="limit"
      :page-sizes="[3, 5, 7, 9]"
      :background="true"
      layout=" prev, pager, next, jumper,->,total, sizes,"
      :total="400"
    />
  </el-card>
</template>

<script setup lang="ts">
//引入组合式API函数
import { ref } from 'vue'
//当前页码
let pageNo = ref<number>(1)
//每一页展示的数据
let limit = ref<number>(3)
</script>

<style lang="scss" scoped></style>

二、数据模块

1、API

1)api函数

//src\api\product\trademark\index.ts
//书写品牌管理模块接口
import request from '@/utils/request'
//品牌管理模块接口地址
enum API {
  //获取已有品牌接口
  TRADEMARK_URL = '/admin/product/baseTrademark/',
}
//获取一样已有的品牌的接口方法
//page:获取第几页 ---默认第一页
//limit:获取几个已有品牌的数据
export const reqHasTrademark = (page: number, limit: number) =>
  request.get<any, any>(API.TRADEMARK_URL + `${page}/${limit}`)

2)获取数据

我们获取数据没有放在pinia中,二是放在组件中挂载时获取数据

//src\views\product\trademark\index.vue
<script setup lang="ts">
import { reqHasTrademark } from '@/api/product/trademark'
//引入组合式API函数
import { ref, onMounted } from 'vue'
//当前页码
let pageNo = ref<number>(1)
//每一页展示的数据
let limit = ref<number>(3)
//存储已有品牌数据总数
let total = ref<number>(0)
//存储已有品牌的数据
let trademarkArr = ref<any>([])
//获取已有品牌的接口封装为一个函数:在任何情况下向获取数据,调用次函数即可
const getHasTrademark = async (pager = 1) => {
  //当前页码
  pageNo.value = pager
  let result = await reqHasTrademark(pageNo.value, limit.value)
  console.log(result)
  if (result.code == 200) {
    //存储已有品牌总个数
    total.value = result.data.total
    trademarkArr.value = result.data.records
    console.log(trademarkArr)
    
  }
}
//组件挂载完毕钩子---发一次请求,获取第一页、一页三个已有品牌数据
onMounted(() => {
  getHasTrademark()
})
</script>

2、数据展示

在数据展示模块,我们使用了element-plus的el-table,下面组要讲解属性和注意点。

1)data属性:显示的数据

比如我们这里绑定的trademarkArr是个三个对象的数组,就会多出来3行。

<el-table style="margin: 10px 0px" border :data="trademarkArr">
            <el-table-column label="序号" width="80px" align="center"></el-table-column>
            <el-table-column label="品牌名称"></el-table-column>
            <el-table-column label="品牌LOGO"></el-table-column>
            <el-table-column label="品牌操作"></el-table-column>
        </el-table>

2)el-table-column的type属性:对应列的类型。 如果设置了selection则显示多选框; 如果设置了 index 则显示该行的索引(从 1 开始计算); 如果设置了 expand 则显示为一个可展开的按钮


<el-table-column label="序号" width="80px" align="center" type="index"></el-table-column>

3)el-table-column的prop属性:字段名称 对应列内容的字段名, 也可以使用 property属性

注意:因为我们之前已经绑定了数据,所以在这里直接使用数据的属性tmName

<el-table-column label="品牌名称" prop="tmName"></el-table-column>

4)el-table-column的插槽

为什么要使用插槽呢?因为prop属性虽然能够展示数据,但是他默认是div,如果我们的图片使用prop展示的话,会展示图片的路径。因此如果想展示图片或者按钮,我们就要使用插槽

<el-table-column label="品牌LOGO">
                <template #="{ row, $index}">
                    <img :src="row.logoUrl" width="100px" height="100px"/>
                </template>
            </el-table-column>

注意:row就是我们的trademarkArr的每一个数据(对象)

三、品牌类型定义

API中的以及组件中。 

//src\api\product\trademark\type.ts
export interface ResponseData {
  code: number
  message: string
  ok: boolean
}

//已有的品牌的ts数据类型
export interface TradeMark {
  id?: number
  tmName: string
  logoUrl: string
}

//包含全部品牌数据的ts类型
export type Records = TradeMark[]

//获取的已有全部品牌的数据ts类型
export interface TradeMarkResponseData extends ResponseData {
  data: {
    records: Records
    total: number
    size: number
    current: number
    searchCount: boolean
    pages: number
  }
}

四、分页展示数据

此部分主要是俩个功能,第一个是当点击分页器页数时能跳转到对应的页数。第二个是每页展示的数据条数能正确显示

1、跳转页数函数

这里我们绑定的点击回调直接用的是之前写好的发送请求的回调。可以看出,发送请求的回调函数是有默认的参数:

1.注意:因为current-change方法时element-plus封装好的,它会给父组件传递并注入一个参数(点击的页码),所以相当于把这个参数传递给了getHasTrademark函数,因此能够跳转到正确的页码数

<el-pagination 
        v-model:current-page="pageNo" 
        v-model:page-size="limit" 
        :page-sizes="[3, 5, 7, 9]"
        :background="true" 
        layout=" prev, pager, next, jumper,->,total, sizes," 
        :total="total" 
        @current-change = "getHasTrademark"
        />

//src/views/product/trademark/index.vue
//获取已有品牌的接口封装为一个函数:在任何情况下向获取数据,调用次函数即可
const getHasTrademark = async (pager = 1) => {
  //当前页码
  pageNo.value = pager
  let result: TradeMarkResponseData = await reqHasTrademark(
    pageNo.value,
    limit.value,
  )
  if (result.code == 200) {
    //存储已有品牌总个数
    total.value = result.data.total
    trademarkArr.value = result.data.records
  }
}

2、每页展示数据条数

<el-pagination 
        v-model:current-page="pageNo" 
        v-model:page-size="limit" 
        :page-sizes="[3, 5, 7, 9]"
        :background="true" 
        layout=" prev, pager, next, jumper,->,total, sizes," 
        :total="total" 
        @current-change = "getHasTrademark"
        @size-change = "sizeChange"
        />

//当下拉菜单发生变化的时候触发此方法
//这个自定义事件,分页器组件会将下拉菜单选中数据返回
const sizeChange = () => {
  //当前每一页的数据量发生变化的时候,当前页码归1
  getHasTrademark()
  console.log(123)
}

五、dialog对话框静态搭建 

1、对话框的标题&&显示隐藏

v-model:属性用户控制对话框的显示与隐藏的 true显示 false隐藏

title:设置对话框左上角标题

<el-dialog v-model="dialogFormVisible" title="Shipping address" width="800">
    </el-dialog>

2、表单项

    <el-form style="width: 80%">
      <el-form-item label="品牌名称" label-width="100px" prop="tmName">
        <el-input
          placeholder="请您输入品牌名称"
          v-model="trademarkParams.tmName"
        ></el-input>
      </el-form-item>
      <el-form-item label="品牌LOGO" label-width="100px" prop="logoUrl">
        <!-- upload组件属性:action图片上传路径书写/api,代理服务器不发送这次post请求  -->
        <el-upload
          class="avatar-uploader"
          action="/api/admin/product/fileUpload"
          :show-file-list="false"
          :on-success="handleAvatarSuccess"
          :before-upload="beforeAvatarUpload"
        >
          <img
            v-if="trademarkParams.logoUrl"
            :src="trademarkParams.logoUrl"
            class="avatar"
          />
          <el-icon v-else class="avatar-uploader-icon">
            <Plus />
          </el-icon>
        </el-upload>
      </el-form-item>
    </el-form>

3、确定与取消按钮

<template #footer>
  <el-button type="primary" size="default" @click="cancel">取消</el-button>
  <el-button type="primary" size="default" @click="confirm">确定</el-button>
</template>

六、新增品牌

1、api

//src/api/product/trademark/index.ts
//书写品牌管理模块接口
import request from '@/utils/request'
import type { TradeMarkResponseData, TradeMark } from './type'
//品牌管理模块接口地址
enum API {
  。。。。。。
  //添加品牌
  ADDTRADEMARK_URL = '/admin/product/baseTrademark/save',
  //修改已有品牌
  UPDATETRADEMARK_URL = '/admin/product/baseTrademark/update',
}
。。。。。。
//添加与修改已有品牌接口方法
export const reqAddOrUpdateTrademark = (data: TradeMark) => {
  //修改已有品牌的数据
  if (data.id) {
    return request.put<any, any>(API.UPDATETRADEMARK_URL, data)
  } else {
    //新增品牌
    return request.post<any, any>(API.ADDTRADEMARK_URL, data)
  }
}

2、收集品牌名称

 1)收集数据

<el-form style="width: 80%">
            <el-form-item label="品牌名称" label-width="100px" prop="tmName">
                <el-input placeholder="请您输入品牌名称" v-model="trademarkParams.tmName"></el-input>
            </el-form-item>
            <el-form-item label="品牌LOGO" label-width="100px" prop="logoUrl">
                <!-- upload组件属性:action图片上传路径书写/api,代理服务器不发送这次post请求  -->
                <el-upload class="avatar-uploader" action="/api/admin/product/fileUpload" :show-file-list="false"
                    :on-success="handleAvatarSuccess" :before-upload="beforeAvatarUpload">
                    <img v-if="trademarkParams.logoUrl" :src="trademarkParams.logoUrl" class="avatar" />
                    <el-icon v-else class="avatar-uploader-icon">
                        <Plus />
                    </el-icon>
                </el-upload>
            </el-form-item>
        </el-form>


//定义收集新增品牌数据
let trademarkParams = reactive<TradeMark>({
    tmName: '',
    logoUrl: '',
})

2)upload组件的属性介绍

<!-- upload组件属性:action图片上传路径书写/api,代理服务器不发送这次post请求  -->
                <el-upload class="avatar-uploader" action="/api/admin/product/fileUpload" :show-file-list="false"
                    :on-success="handleAvatarSuccess" :before-upload="beforeAvatarUpload">
                    <img v-if="trademarkParams.logoUrl" :src="trademarkParams.logoUrl" class="avatar" />
                    <el-icon v-else class="avatar-uploader-icon">
                        <Plus />
                    </el-icon>
                </el-upload>

class:带的一些样式,需复制到style中

action:图片上传路径需要书写/api,否则代理服务器不发送这次post请求

:show-file-list:是否展示已经上传的文件

:before-upload:上传图片之前的钩子函数

//上传图片组件->上传图片之前触发的钩子函数
const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => {
  //钩子是在图片上传成功之前触发,上传文件之前可以约束文件类型与大小
  //要求:上传文件格式png|jpg|gif 4M
  if (
    rawFile.type == 'image/png' ||
    rawFile.type == 'image/jpeg' ||
    rawFile.type == 'image/gif'
  ) {
    if (rawFile.size / 1024 / 1024 < 4) {
      return true
    } else {
      ElMessage({
        type: 'error',
        message: '上传文件大小小于4M',
      })
      return false
    }
  } else {
    ElMessage({
      type: 'error',
      message: '上传文件格式务必PNG|JPG|GIF',
    })
    return false
  }
}

:on-success图片上传成功钩子(收集了上传图片的地址)

在这里,你将本地的图片上传到之前el-upload组件的action="/api/admin/product/fileUpload"这个地址上,然后on-success钩子会将上传后图片的地址返回

3)上传图片后,用图片代替加号

3、添加品牌

1)点击确定按钮回调

const confirm = async () => {
  //在你发请求之前,要对于整个表单进行校验
  //调用这个方法进行全部表单相校验,如果校验全部通过,在执行后面的语法
  // await formRef.value.validate()
  let result: any = await reqAddOrUpdateTrademark(trademarkParams)
  //添加|修改已有品牌
  if (result.code == 200) {
    //关闭对话框
    dialogFormVisible.value = false
    //弹出提示信息
    ElMessage({
      type: 'success',
      message: trademarkParams.id ? '修改品牌成功' : '添加品牌成功',
    })
    //再次发请求获取已有全部的品牌数据
    getHasTrademark(trademarkParams.id ? pageNo.value : 1)
  } else {
    //添加品牌失败
    ElMessage({
      type: 'error',
      message: trademarkParams.id ? '修改品牌失败' : '添加品牌失败',
    })
    //关闭对话框
    dialogFormVisible.value = false
  }
}

2 )每次点击添加品牌的时候先情况之前的数据

//添加品牌按钮的回调
const addTrademark = () => {
  //对话框显示
  dialogFormVisible.value = true
  //清空收集数据
  trademarkParams.tmName = ''
  trademarkParams.logoUrl = ''
}

七、修改品牌数据 

1、绑定点击函数

其中的row就是当前的数据

<el-button type="primary" size="small" icon="Edit" @click="updateTrademark(row)" />

 2、回调函数

//修改已有品牌的按钮的回调
//row:row即为当前已有的品牌
const updateTrademark = (row: TradeMark) => {
  //对话框显示
  dialogFormVisible.value = true
  //ES6语法合并对象
  Object.assign(trademarkParams, row)
}

3、对确认按钮回调修改

const confirm = async () => {
  。。。。。。。
  if (result.code == 200) {
   。。。
    //弹出提示信息
    ElMessage({
      。。。。
      message: trademarkParams.id ? '修改品牌成功' : '添加品牌成功',
    })
    //再次发请求获取已有全部的品牌数据
    getHasTrademark(trademarkParams.id ? pageNo.value : 1)
  } else {
    //添加品牌失败
    ElMessage({
      。。。。
      message: trademarkParams.id ? '修改品牌失败' : '添加品牌失败',
    })
    。。。。
  }
}

4、设置对话框标题

<el-dialog v-model="dialogFormVisible" :title="trademarkParams.id?'修改品牌':'添加品牌'" width="800">

5、小问题

当我们修改操作之后再点击添加品牌,对话框的title依旧是修改品牌。怎么是因为对话框的title是根据trademarkParams.id来的,我们之前添加品牌按钮操作没有对id进行清除。修改为如下就可

//添加品牌按钮的回调
const addTrademark = () => {
  //对话框显示
  dialogFormVisible.value = true
  //清空收集数据
  trademarkParams.id = 0
  trademarkParams.tmName = ''
  trademarkParams.logoUrl = ''
}

八、品牌管理模块表单校验 

1、表单校验(自定义规则校验,可以简略堪称三步走)

1)绑定参数

<el-form 
ref="formRef" 
:model="trademarkParams" 
:rules="rules" style="width: 80%">

:model:校验的数据

:rules:校验规则 

ref="formRef":表单实例

<el-form-item 
label="品牌名称" 
label-width="100px" 
prop="tmName">
 </el-form-item>

prop:表单元素校验的数据,可以直接使用表单绑定的数据。

2)Rules

//表单校验规则对象
const rules = {
    tmName: [
        //required:这个字段务必校验,表单项前面出来五角星
        //trigger:代表触发校验规则时机[blur、change]
        { required: true, trigger: 'blur', validator: validatorTmName },
    ],
    logoUrl: [{ required: true, validator: validatorLogoUrl }],
}

 3)Rules中写的方法

//品牌自定义校验规则方法
const validatorTmName = (rule: any, value: any, callBack: any) => {
    //是当表单元素触发blur时候,会触发此方法
    //自定义校验规则
    if (value.trim().length >= 2) {
        callBack()
    } else {
        //校验未通过返回的错误的提示信息
        callBack(new Error('品牌名称位数大于等于两位'))
    }
}
//品牌LOGO图片的自定义校验规则方法
const validatorLogoUrl = (rule: any, value: any, callBack: any) => {
    //如果图片上传
    if (value) {
        callBack()
    } else {
        callBack(new Error('LOGO图片务必上传'))
    }
}

2、图片校验

1)图片校验时机

因为img是图片,不好判断。因此使用表单的validate属性,全部校验,放在确认按钮的回调函数中

const confirm = async () => {
  //在你发请求之前,要对于整个表单进行校验
  //调用这个方法进行全部表单相校验,如果校验全部通过,在执行后面的语法
  await formRef.value.validate()//返回的是一个promise对象
 。。。。。。
}

2)清除校验信息

当图片没有上传点击确认后会出来校验的提示信息,我们上传图片后校验信息应该消失。使用表单的clearValidate属性 

//图片上传成功钩子
const handleAvatarSuccess: UploadProps['onSuccess'] = (
  。。。。。。
) => {
  。。。。。。。
  //图片上传成功,清除掉对应图片校验结果
  formRef.value.clearValidate('logoUrl')
}

当我们未填写信息去点击确认按钮时,会弹出2个校验信息。当我们关闭后再打开,校验信息还在。因为,我们需要在添加品牌按钮时清除校验信息。但是因为点击添加品牌,表单还没有加载,所以我们需要换个写法。

//添加品牌按钮的回调
const addTrademark = () => {
  //对话框显示
  dialogFormVisible.value = true
  //清空收集数据
  trademarkParams.id = 0
  trademarkParams.tmName = ''
  trademarkParams.logoUrl = ''
  //第一种写法:ts的问号语法
  formRef.value?.clearValidate('tmName')
  formRef.value?.clearValidate('logoUrl')
  /* nextTick(() => {
    formRef.value.clearValidate('tmName')
    formRef.value.clearValidate('logoUrl')
  }) */
}

同理修改按钮

//修改已有品牌的按钮的回调
//row:row即为当前已有的品牌
const updateTrademark = (row: TradeMark) => {
  //清空校验规则错误提示信息
  nextTick(() => {
    formRef.value.clearValidate('tmName')
    formRef.value.clearValidate('logoUrl')
  })
 。。。。。。
}

九、删除品牌

删除业务要做的事情不多,包括API以及发请求。不过有些点要注意

1、API 

//书写品牌管理模块接口
import request from '@/utils/request'
import type { TradeMarkResponseData, TradeMark } from './type'
//品牌管理模块接口地址
enum API {
  。。。。。。。
  //删除已有品牌
  DELETE_URL = '/admin/product/baseTrademark/remove/',
}
。。。。。。

//删除某一个已有品牌的数据
export const reqDeleteTrademark = (id: number) =>
  request.delete<any, any>(API.DELETE_URL + id)

2、绑定函数

这里使用了一个气泡组件,@confirm绑定的就是回调函数

<el-popconfirm :title="`您确定要删除${row.tmName}?`" width="250px" icon="Delete"
                        @confirm='removeTradeMark(row.id)'>
                        <template #reference>
                            <el-button type="primary" size="small" icon="Delete"></el-button>
                        </template>
                    </el-popconfirm>

 3、回调函数

//气泡确认框确定按钮的回调
const removeTradeMark = async (id: number) => {
  //点击确定按钮删除已有品牌请求
  let result = await reqDeleteTrademark(id)
  if (result.code == 200) {
    //删除成功提示信息
    ElMessage({
      type: 'success',
      message: '删除品牌成功',
    })
    //再次获取已有的品牌数据
    getHasTrademark(
      trademarkArr.value.length > 1 ? pageNo.value : pageNo.value - 1,
    )
  } else {
    ElMessage({
      type: 'error',
      message: '删除品牌失败',
    })
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值