【Vue3+Ts项目】硅谷甄选 — 品牌管理+平台属性管理+SPU管理+SKU管理

 一、品牌管理模块

1.1 静态模块搭建

使用到element-plus的card、button、table、pagination等组件:src/views/product/trademark/index.vue






 1.2 品牌管理模块数据展示

 1.2.1 书写trademark接口文件

src/api/product/trademark/index.ts

// 书写品牌管理模块接口
import request from '@/utils/request'
import type { TrademarkResponeData } from './type'
// 品牌管理模块接口地址
enum API {
    // 获取已有品牌接口
    TRADEMARK_URL = '/admin/product/baseTrademark/'
}

// 获取已有品牌的接口方法
// page:获取第几页 ---默认第一页
// limit:获取几个已有品牌的数据
export const reqHasTrademark = (page: number, limit: number) => request.get(API.TRADEMARK_URL + `${page}/${limit}`)

 1.2.2 接口数据ts类型定义

src/api/product/trademark/type.ts

export interface ResponeData {
    code: number
    message: string
    ok: boolean
}

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

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

// 获取的已有全部品牌的数据ts类型
export interface TrademarkResponeData extends ResponeData {
    data: {
        records: Records
        total: number
        size: number
        current: number
        orders: []
        optimizeCountSql: boolean
        hitCount: boolean
        countId: null
        maxLimit: null
        searchCount: boolean
        pages: number
    }
}

1.2.3 动态获取数据并展示

src/views/product/trademark/index.vue

table-column:默认展示数据用div,通过prop属性展示数据;如果需要自定义列的内容,可以使用插槽#来展示内容。




 1.3 品牌管理分页展示数据

给pagination组件标签添加current-change、size-change事件,书写对应方法,在当前页码和下拉菜单(每页展示的数据条数)发生变化时触发getHasTrademark回调,重新获取数据进行展示。






// 分页器当前页码发生变化的时候触发
// 对于当前页码发生变化自定义事件,组件pagination父组件回传了数据(当前的页码)
// const changePageNo = () =>{
//   // 当前页码发生变化的时候再次发送请求获取对应已有品牌数据展示
//   getHasTrademark()
// }

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

 1.4 对话框dialog(新增|修改品牌)

1.4.1 定义新增|修改接口

 src/api/product/trademark/index.ts

......
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(API.UPDATETRADEMARK_URL, data)
    } else {
        // 新增品牌
        return request.post(API.ADDTRADEMARK_URL, data)
    }
}

1.4.2 新增|修改业务逻辑实现

src/views/product/trademark/index.vue  

图片大小计算:返回的rawFile.size是字节,1024字节 = 1K ,1024K = 1M, 1024M = 1G,

1024G = 1T

PS:表单校验步骤及说明可参考该文章 2.5:【Vue3+Ts项目】硅谷甄选 — 路由配置+登录模块+layout组件+路由鉴权-CSDN博客 


......


添加品牌

......


    


......


  
    
      
        
      
      
        
          
          
            
          
        
      
    
    
    
  




import { ElMessage, UploadProps } from 'element-plus'
import { ref, onMounted, reactive, nextTick } from 'vue'
import { reqHasTrademark, reqAddOrUpdateTrademark } from '@/api/product/trademark'
import type { Records, TrademarkResponeData, Trademark } from '@/api/product/trademark/type'

......

// 控制对话框显示与隐藏
let dialogFormVisible = ref(false)
// 定义收集新增品牌数据
let trademarkParams = reactive({
  tmName: '',
  logoUrl: ''
})
// 获取el-form组件实例
let formRef = ref()

......

// 添加品牌按钮的回调
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')
  })
  //对话框显示
  dialogFormVisible.value = true;
  Object.assign(trademarkParams, row)
}
//对话框底部取消按钮
const cancel = () => {
  //对话框隐藏
  dialogFormVisible.value = false;
}
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;
  }
}

// 上传图片组件 -> 上传图片之前触发的钩子函数
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.error({
      type: 'error',
      message: '上传文件格式务必PNG|JPG|GIF'
    })
    return false
  }
}

// 图片上传成功钩子
const handleAvatarSuccess: UploadProps['onSuccess'] = (response, uploadFile) => {
  // response:即当前这次上传图片post请求服务器返回的数据
  // 收集上传图片的地址,添加一个新的品牌的时候带给服务器
  trademarkParams.logoUrl = response.data
  // 图片上传成功,清除掉对应图片校验错误提示信息
  formRef.value.clearValidate('logoUrl')
}

// 品牌名称自定义校验规则方法
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图片务必上传'))
  }
}

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

1.5 品牌管理删除业务

使用element-plus气泡确认框( Popconfirm)来弹出删除提示。

src/views/product/trademark/index.vue  


    




import { reqHasTrademark, reqAddOrUpdateTrademark, reqDeleteTrademark } from '@/api/product/trademark'

// 气泡确认框确定按钮的回调
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: '删除品牌失败'
    })
  }
}

 二、属性管理模块

2.1 静态模块搭建 

三级分类在后续SPU管理模块也会使用到,所以将三级分类封装成一个全局组件更方便使用。 

2.1.1 分类全局组件

使用el-select下拉菜单实现三级分类全局组件的静态搭建:src/components/Category/index.vue





注册全局组件:src/components/index.ts

import Category from './Category/index.vue'

// 全局组件对象
const allGlobalComponents: any = {
  Category,
}

 PS:封装全局组件具体的实现可参考此文章:vue3---自定义插件注册全局对象-CSDN博客 

 2.1.2 属性管理组件

引入三级分类全局组件+使用el-table展示属性相关数据,实现属性管理组件的静态搭建:rc/views/product/attr/index.vue






2.2 分类全局组件(Category)

分类全局组件挂载时获取一级分类,将获取到的一级分类数据和ID存储在仓库中(方便父组件使用分类ID获取属性相关数据), 通过一级分类的ID获取二级分类,二级分类的ID获取三级分类。

2.2.1 接口

① 接口定义

src/api/product/attr/index.ts

// 这里书写属性相关的API文件
import request from '@/utils/request'
import type { CategoryResponseData } from './type'

// 属性管理模块接口地址
enum API {
    // 获取一级分类接口地址
    C1_URL = '/admin/product/getCategory1',
    // 获取二级分类接口地址
    C2_URL = '/admin/product/getCategory2/',
    // 获取三级分类接口地址
    C3_URL = '/admin/product/getCategory3/',
}

// 获取一级分类的接口方法
export const reqC1 = () => request.get(API.C1_URL)
// 获取二级分类的接口方法
export const reqC2 = (category1: number | string) => request.get(API.C2_URL + category1)
// 获取三级分类的接口方法
export const reqC3 = (category2: number | string) => request.get(API.C3_URL + category2)

 ② 数据ts类型定义

src/api/product/attr/type.ts

// 分类相关的数据ts类型
export interface ResponseData {
    code: number
    message: string
    ok: boolean
}

// 分类ts类型
export interface CategoryObj {
    id: number | string
    name: string
    category1Id?: number
    category2Id?: number
}

// 相应的分类接口返回数据类型
export interface CategoryResponseData extends ResponseData {
    data: CategoryObj[]
}

2.2.2 小仓库

① 创建小仓库

 src/store/modules/attr/category.ts

// 商品分类全局组件的小仓库
import { defineStore } from 'pinia'
import { reqC1, reqC2, reqC3 } from '@/api/product/attr'
import type { CategoryResponseData } from '@/api/product/attr/type'
import type { CategoryState } from './types/type'
let useCategoryStore = defineStore('Category', {
    state: (): CategoryState => {
        return {
            // 存储一级分类的数据
            c1Arr: [],
            // 存储一级分类的ID
            c1Id: '',
            // 存储对应一级分类下二级分类的数据
            c2Arr: [],
            // 存储二级分类的ID
            c2Id: '',
            // 存储三级分类的数据
            c3Arr: [],
            // 存储三级分类的ID
            c3Id: ''
        }
    },
    actions: {
        // 获取一级分类的方法
        async getC1() {
            // 发请求获取一级分类的数据
            let result: CategoryResponseData = await reqC1()
            if (result.code === 200) {
                this.c1Arr = result.data
            }
        },
        // 获取二级分类的方法
        async getC2() {
            // 获取对应一级分类下的二级分类的数据
            let result: CategoryResponseData = await reqC2(this.c1Id)
            if (result.code === 200) {
                this.c2Arr = result.data
            }
        },
        // 获取三级分类的方法
        async getC3() {
            let result: CategoryResponseData = await reqC3(this.c2Id)
            if (result.code === 200) {
                this.c3Arr = result.data
            }
        }
    },
    getters: {}
})

export default useCategoryStore

② state数据ts类型定义

src/store/modules/types/type.ts 

import type { CategoryObj } from '@/api/product/attr/type'

// 定义分类仓库state对象的ts类型
export interface CategoryState {
  c1Id: string | number
  c1Arr: CategoryObj[]
  c2Arr: CategoryObj[]
  c2Id: string | number
  c3Arr: CategoryObj[]
  c3Id: string | number
}

 2.2.3 业务实现

src/components/Category/index.vue





PS:当父组件传递scene为1时,下拉菜单select禁用,scene为0时,下拉菜单select正常使用。(Category中select组件需加上 :disabled="scene === 1 ? true : false") 

2.3 属性管理主组件(attr)

 提升开发效率的小Tips①:解析格式化JSON的网站(方便查看数据的结构):JSON在线解析及格式化验证 - JSON.cn 

2.3.1 接口

① 接口定义 

src/api/product/attr/index.ts

import type { ......, AttrResponeData, Attr  } from './type'

enum API {
    ......
    // 获取分类下已有属性与属性值
    ATTR_URL = '/admin/product/attrInfoList/',
    // 添加或修改已有的属性的接口
    ADDORUPDATEATTR_URL = '/admin/product/saveAttrInfo',
    //删除某一个已有的属性
    DELETEATTR_URL = '/admin/product/deleteAttr/',
}

// 获取对应分类下已有的属性与属性值接口
export const reqAttr = (category1Id: string | number, category2Id: string | number, category3Id: string | number) => request.get(API.ATTR_URL + `${category1Id}/${category2Id}/${category3Id}`)

// 新增或修改已有属性的接口
export const reqAddOrUpdateAttr = (data: Attr) => request.post(API.ADDORUPDATEATTR_URL, data)

//删除某一个已有的属性业务
export const reqRemoveAttr = (attrId: number) => request.delete(API.DELETEATTR_URL + attrId)

 ② 数据ts类型定义

src/api/product/attr/type.ts

// 属性与属性值的ts类型

// 属性值对象的ts类型
export interface AttrValue {
    id?: number
    valueName: string
    attrId?: number
    flag: boolean
}

// 存储每一个属性值的数组类型
export type AttrValueList = AttrValue[]

// 属性对象的ts类型
export interface Attr {
    id?: number
    attrName: string
    categoryId: number | string
    categoryLevel: number
    attrValueList: AttrValueList
}

// 存储每一个属性对象的数组ts类型
export type AttrList = Attr[]

// 属性接口返回的数据ts类型
export interface AttrResponeData extends ResponseData {
    data: AttrList
}

2.3.2 业务实现

src/views/product/attr/index.vue

属性管理业务包括:展示数据、添加/修改数据、删除数据。

  • 数据展示:通过三级分类下拉菜单存储的分类ID请求属性与属性值数据,使用el-table进行展示。
  • 添加/修改数据:通过scene作为切换标识,进行数据展示与添加/修改数据页面切换,然后收集属性与属性值数据,发请求进行保存。
  • 删除数据:使用el-popconfirm进行删除确认发请求。





Object.assign:Object.assign为浅拷贝,如果修改属性时,直接使用Object.assign(attrParams, row)将已有的属性对象赋值给attrParams对象,会出现修改了属性之后点击取消按钮返回列表时,属性还是修改了;可以使用JSON方法进行深拷贝Object.assign(attrParams, JSON.parse(JSON.stringify(row)))。(关于深拷贝和浅拷贝的区别可以参考文章:js中深拷贝和浅拷贝的理解,它们的区别是什么-CSDN博客)

三、SPU管理模块 

3.1 SPU和SKU概念介绍  

SPU:电商术语,代表的是一个标准化产品单元。(类)

SPU组成:产品品牌名称+描述+产品图片介绍+销售属性【整个项目销售属性一共三个:颜色、版本、尺码】

例如,华为公司的品牌名称是华为,华为就是一个产品单元。

SKU:库存最小单位。(实例) 

3.2 SPU实现

3.2.1 接口 

① 接口定义

src/api/product/spu/index.ts

// SPU管理模块的接口
import request from "@/utils/request";
import { SpuData, HasSpuResponeData, AllTrademark, SpuHasImg, SaleAttrResponseData, HasSaleAttrResponseData, SkuData, SkuInfoData } from './type'

enum API {
    // 获取已有的SPU的数据
    HASSPU_URL = '/admin/product/',
    // 获取全部品牌的数据
    ALLTRADEMARK_URL = '/admin/product/baseTrademark/getTrademarkList',
    // 获取某个SPU下的全部的售卖产品的图片数据
    IMAGE_URL = '/admin/product/spuImageList/',
    // 获取某一个SPU下全部的已有的销售属性接口地址
    SPUHASSALEATTR_URL = '/admin/product/spuSaleAttrList/',
    // 获取整个项目全部的销售属性[颜色、版本、尺码]
    ALLSALEATTR_URL = '/admin/product/baseSaleAttrList',
    // 追加一个新的SPU
    ADDSPU_URL = '/admin/product/saveSpuInfo',
    // 更新已有的SPU
    UPDATESPU_URL = '/admin/product/updateSpuInfo',
    //追加一个新增的SKU地址
    ADDSKU_URL = '/admin/product/saveSkuInfo',
    //查看某一个已有的SPU下全部售卖的商品
    SKUINFO_URL = '/admin/product/findBySpuId/',
    //删除已有的SPU
    REMOVESPU_URL = '/admin/product/deleteSpu/',
}

// 获取某一个三级分类下已有的SPU数据
export const reqHasSpu = (page: number, limit: number, category3Id: number | string) => request.get(API.HASSPU_URL + `${page}/${limit}?category3Id=${category3Id}`)
// 获取全部的SPU的品牌的数据
export const reqAllTrademark = () => request.get(API.ALLTRADEMARK_URL)
// 获取某一个已有的SPU下全部商品的图片地址
export const reqSpuImageList = (spuId: number) => request.get(API.IMAGE_URL + spuId)
// 获取某一个已有的SPU拥有多少个销售属性
export const reqSpuHasSaleAttr = (spuId: number) => request.get(API.SPUHASSALEATTR_URL + spuId)
// 获取全部的销售属性
export const reqAllSaleAttr = () => request.get(API.ALLSALEATTR_URL)
// 添加一个新的SPU
// 更新已有的SPU
// data:即为新增的SPU|已有的SPU
export const reqAddOrUpdateSpu = (data: SpuData) => {
    // 如果SPU对象拥有ID,更新已有的SPU
    if (data.id) {
        return request.post(API.UPDATESPU_URL, data)
    } else {
        return request.post(API.ADDSPU_URL, data)
    }
}
//添加SKU的请求方法
export const reqAddSku = (data: SkuData) => request.post(API.ADDSKU_URL, data)

//获取SKU数据
export const reqSkuList = (spuId: number | string) => request.get(API.SKUINFO_URL + spuId)

//删除已有的SPU
export const reqRemoveSpu = (spuId: number | string) => request.delete(API.REMOVESPU_URL + spuId)

 ② 数据ts类型定义

src/api/product/spu/type.ts

// 服务器全部接口返回的数据类型
export interface ResponeData {
    code: number
    message: string
    ok: boolean
}

// SPU数据的ts类型
export interface SpuData {
    category3Id: string | number
    id?: number
    spuName: string
    tmId: number | string
    description: string
    spuImageList: null | SpuImg[]
    spuSaleAttrList: null | SaleAttr[]
}

// 数组:元素都是已有SPU数据类型
export type Records = SpuData[]

// 定义获取已有的SPU接口返回的数据ts类型
export interface HasSpuResponeData extends ResponeData {
    data: {
        records: Records
        total: number
        size: number
        current: number
        searchCount: boolean
        pages: number
    }
}

// 品牌数据的ts类型
export interface Trademark {
    id: number
    tmName: string
    logoUrl: string
}

// 品牌接口返回的数据ts类型
export interface AllTrademark extends ResponeData {
    data: Trademark[]
}

// 商品图片的ts类型
export interface SpuImg {
    id?: number
    imgName?: string
    imgUrl?: string
    createTime?: string
    updateTime?: string
    spuId?: number
    name?: string
    url?: string
}
// 已有的SPU照片墙数据的类型
export interface SpuHasImg extends ResponeData {
    data: SpuImg[]
}

// 已有的销售属性值对象ts类型
export interface SaleAttrValue {
    id?: number
    createTime?: null
    updateTime?: null
    spuId?: number
    baseSaleAttrId: number | string
    saleAttrValueName: string
    saleAttrName?: string
    isChecked?: null
}

// 存储已有的销售属性值数组类型
export type SpuSaleAttrValueList = SaleAttrValue[]

// 销售属性对象ts类型
export interface SaleAttr {
    id?: number
    createTime?: null
    updateTime?: null
    spuId?: number
    baseSaleAttrId: number | string
    saleAttrName: string
    spuSaleAttrValueList: SpuSaleAttrValueList
    flag?: boolean
    saleAttrValue?: string
}

// SPU已有的销售属性接口返回数据ts类型
export interface SaleAttrResponseData extends ResponeData {
    data: SaleAttr[]
}

// 已有的全部SPU的返回数据ts类型
export interface HasSaleAttr {
    id: number
    name: string
}

export interface HasSaleAttrResponseData extends ResponeData {
    data: HasSaleAttr[]
}

export interface Attr {
    attrId: number | string //平台属性的ID
    valueId: number | string //属性值的ID
}

export interface saleArr {
    saleAttrId: number | string //属性ID
    saleAttrValueId: number | string //属性值的ID
}
export interface SkuData {
    category3Id: string | number //三级分类的ID
    spuId: string | number //已有的SPU的ID
    tmId: string | number //SPU品牌的ID
    skuName: string //sku名字
    price: string | number //sku价格
    weight: string | number //sku重量
    skuDesc: string //sku的描述
    skuAttrValueList?: Attr[]
    skuSaleAttrValueList?: saleArr[]
    skuDefaultImg: string //sku图片地址
}

//获取SKU数据接口的ts类型
export interface SkuInfoData extends ResponeData {
    data: SkuData[]
}

 3.2.2 业务实现

SPU模块包括:

  • Category组件
  • table表格展示数据
  • spuForm组件(即spu的增删改模块)
  • skuForm组件(即sku的添加删除模块) 

 src/views/product/spu/index.vue 






  src/views/product/spu/spuForm.vue





  src/views/product/spu/skuForm.vue





四、SKU管理模块

 4.1 SKU实现

4.1.1 接口

① 接口定义 

 src/api/product/sku/index.ts

// SKU模块接口管理
import request from '@/utils/request'
import type { SkuResponseData, SkuInfoData } from './type'
// 枚举地址
enum API {
  // 获取已有的商品的数据-SKU
  SKU_URL = '/admin/product/list/',
  // 上架
  SALE_URL = '/admin/product/onSale/',
  // 下架
  CANCELSALE_URL = '/admin/product/cancelSale/',
  //获取商品详情的接口
  SKUINFO_URL = '/admin/product/getSkuInfo/',
  //删除已有的商品
  DELETESKU_URL = '/admin/product/deleteSku/',
}
// 获取商品SKU的接口
export const reqHasSku = (page: number, limit: number) =>
  request.get(API.SKU_URL + `${page}/${limit}`)
// 已有商品上架请求
export const reqSaleSku = (skuId: number) =>
  request.get(API.SALE_URL + skuId)
// 下架的请求
export const reqCancelSaleSku = (skuId: number) =>
  request.get(API.CANCELSALE_URL + skuId)
//获取商品详情的接口
export const reqSkuInfo = (skuId: number) =>
  request.get(API.SKUINFO_URL + skuId)
//删除某一个已有的商品
export const reqRemoveSku = (skuId: number) =>
  request.delete(API.DELETESKU_URL + skuId)

② 数据ts类型定义

src/api/product/sku/type.ts

export interface ResponseData {
  code: number
  message: string
  ok: boolean
}
//定义SKU对象的ts类型
export interface Attr {
  id?: number
  attrId: number | string //平台属性的ID
  valueId: number | string //属性值的ID
}
export interface saleArr {
  id?: number
  saleAttrId: number | string //属性ID
  saleAttrValueId: number | string //属性值的ID
}
export interface SkuData {
  category3Id?: string | number //三级分类的ID
  spuId?: string | number //已有的SPU的ID
  tmId?: string | number //SPU品牌的ID
  skuName?: string //sku名字
  price?: string | number //sku价格
  weight?: string | number //sku重量
  skuDesc?: string //sku的描述
  skuAttrValueList?: Attr[]
  skuSaleAttrValueList?: saleArr[]
  skuDefaultImg?: string //sku图片地址
  isSale?: number //控制商品的上架与下架
  id?: number
}

//获取SKU接口返回的数据ts类型
export interface SkuResponseData extends ResponseData {
  data: {
    records: SkuData[]
    total: number
    size: number
    current: number
    orders: []
    optimizeCountSql: boolean
    hitCount: boolean
    countId: null
    maxLimit: null
    searchCount: boolean
    pages: number
  }
}

//获取SKU商品详情接口的ts类型
export interface SkuInfoData extends ResponseData {
  data: SkuData
}

4.1.2 业务实现

src/views/product/sku/index.vue  






你可能感兴趣的:(vue.js,前端,javascript)