一、SKU模块静态页面
src\views\product\sku\index.vue
<template>
<el-card>
<el-table border style="margin: 10px 0px">
<el-table-column type="index" label="序号" width="80px"></el-table-column>
<el-table-column
label="名称"
width="80px"
show-overflow-tooltip
></el-table-column>
<el-table-column
label="描述"
width="300px"
show-overflow-tooltip
></el-table-column>
<el-table-column label="图片" width="300px"></el-table-column>
<el-table-column label="重量" width="300px"></el-table-column>
<el-table-column label="价格" width="300px"></el-table-column>
<el-table-column
label="操作"
width="300px"
fixed="right"
></el-table-column>
</el-table>
<el-pagination
v-model:current-page="pageNo"
v-model:page-size="pageSize"
:page-sizes="[10, 20, 30, 40]"
:background="true"
layout="prev, pager, next, jumper, ->,sizes,total "
:total="400"
/>
</el-card>
</template>
二、获取展示数据
2.1API
src\api\product\sku\index.ts
//SKU模块接口管理
import request from '@/utils/request'
import type { SkuResponseData} from './type'
//枚举地址
enum API {
//获取已有的商品的数据-SKU
SKU_URL = 'http://114.115.179.162:8022/prod-api/admin/product/list/',
}
//获取商品SKU的接口
export const reqSkuList = (page: number, limit: number) => {
return request.get<any, SkuResponseData>(API.SKU_URL + `${page}/${limit}`)
}
2.2 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
}
}
2.3 组件获取数据
<script setup lang="ts">
import { ref, onMounted } from "vue";
import { reqSkuList } from "@/api/product/sku/index.ts";
import type { SkuResponseData, SkuData } from "@/api/product/sku/type.ts";
//当前页码
let pageNo = ref<number>(1);
//每一页展示的数据
let pageSize = ref<number>(10);
//存储已有品牌数据总数
let total = ref<number>(0);
//存储已有sku的数据
let skuArr = ref<SkuData[]>([]);
const getHasSku = async (pager = 1) => {
//修改当前页码
pageNo.value = pager;
let result: SkuResponseData = await reqSkuList(pageNo.value, pageSize.value);
console.log(result);
if (result.code == 200) {
skuArr.value = result.data.records;
total.value = result.data.total;
}
};
//组件挂载完毕钩子---发一次请求,获取第一页、一页三个已有品牌数据
onMounted(() => {
getHasSku();
});
//当下拉菜单发生变化的时候触发此方法
//这个自定义事件,分页器组件会将下拉菜单选中数据返回
const sizeChange = () => {
//当前每一页的数据量发生变化的时候,当前页码归1
getHasSku();
};
</script>
2.4 展示数据
<el-table border style="margin: 10px 0px" :data="skuArr">
<el-table-column type="index" label="序号" width="80px"></el-table-column>
<el-table-column
prop="skuName"
label="名称"
width="80px"
show-overflow-tooltip
></el-table-column>
<el-table-column
prop="skuDesc"
label="描述"
width="300px"
show-overflow-tooltip
></el-table-column>
<el-table-column label="图片" width="300px">
<template #="{ row, $index }">
<img
:src="row.skuDefaultImg"
alt=""
style="width: 100px; height: 100px"
/>
</template>
</el-table-column>
<el-table-column
label="重量"
width="300px"
prop="weight"
></el-table-column>
<el-table-column
label="价格"
width="300px"
prop="price"
></el-table-column>
<el-table-column label="操作" width="300px" fixed="right">
<el-button type="primary" size="small" icon="Top"></el-button>
<el-button type="primary" size="small" icon="Edit"></el-button>
<el-button type="primary" size="small" icon="InfoFilled"></el-button>
<el-button type="primary" size="small" icon="Delete"></el-button>
</el-table-column>
</el-table>
2.5分页器
//当下拉菜单发生变化的时候触发此方法
//这个自定义事件,分页器组件会将下拉菜单选中数据返回
const sizeChange = () => {
//当前每一页的数据量发生变化的时候,当前页码归1
getHasSku();
};
注意:在这里切换页码和切换每页数据条数的回调不同是因为:它们都能对函数注入数据,切换页码注入的是点击的页码数,因此我们可以直接使用getHasSku作为他的回调。切换每页数据条数注入的是切换的页码条数,我们希望切换后跳转到第一页,因此使用handler,间接调用getHasSku。
三、上架下架按钮
3.1 API
//上架
SALE_URL = '/admin/product/onSale/',
//下架的接口
CANCELSALE_URL = '/admin/product/cancelSale/',
//已有商品上架的请求
export const reqSaleSku = (skuId: number) => {
return request.get<any, any>(API.SALE_URL + skuId)
}
//下架的请求
export const reqCancelSale = (skuId: number) => {
return request.get<any, any>(API.CANCELSALE_URL + skuId)
}
由于没有返回数据,所以没有ts类型
3.2 上架下架回调
流程:发请求->更新页面
//商品的上架与下架的操作
const updateSale = async (row: SkuData) => {
//如果当前商品的isSale==1,说明当前商品是上架的额状态->更新为下架
//否则else情况与上面情况相反
if (row.isSale == 1) {
//下架操作
await reqCancelSale(row.id as number)
//提示信息
ElMessage({ type: 'success', message: '下架成功' })
//发请求获取当前更新完毕的全部已有的SKU
getHasSku(pageNo.value)
} else {
//下架操作
await reqSaleSku(row.id as number)
//提示信息
ElMessage({ type: 'success', message: '上架成功' })
//发请求获取当前更新完毕的全部已有的SKU
getHasSku(pageNo.value)
}
}
3.3 更新按钮
更新按钮这里没有业务。个人觉得是因为SKU的编写在SPU已经做完了。防止业务逻辑混乱
//更新已有的SKU
const updateSku = ()=>{
ElMessage({
type:'success',
message:'keson正在努力开发中~~~'
})
}
四、商品详情静态搭建
4.1Drawer 抽屉
描述:呼出一个临时的侧边栏, 可以从多个方向呼出
//控制抽屉显示与隐藏的字段
let drawer = ref<boolean>(false);
....
//查看商品详情按钮的回调
const findSku = async (row: SkuData) => {
//显示抽屉
drawer.value = true;
//获取已有的商品详情数据
let result:SkuInfoData =await reqSkuInfo(row.id as number)
console.log(result)
//存储已有的SKU
skuInfo.value = result.data
};
4.2 Layout 布局
通过基础的 24 分栏,迅速简便地创建布局。
src\views\product\sku\index.vue
<el-drawer v-model="drawer" >
<template #header>
<h4>商品详情</h4>
</template>
<template #default>
<el-row style="margin: 10px 0">
<el-col :span="6">名称:</el-col>
<el-col :span="18">{{ skuInfo.skuName }}</el-col>
</el-row>
<el-row style="margin: 10px 0">
<el-col :span="6">描述:</el-col>
<el-col :span="18">{{ skuInfo.skuDesc }}</el-col>
</el-row>
<el-row style="margin: 10px 0">
<el-col :span="6">价格(元):</el-col>
<el-col :span="18">{{ skuInfo.price}}</el-col>
</el-row>
<el-row style="margin: 10px 0">
<el-col :span="6">平台属性:</el-col>
<el-col :span="18">
<el-tag style="margin: 2px" v-for="item in skuInfo.skuAttrValueList" :key="item.id">{{ item.attrName }}</el-tag>
</el-col>
</el-row>
<el-row style="margin: 10px 0">
<el-col :span="6">销售属性:</el-col>
<el-col :span="18">
<el-tag type="danger" style="margin: 2px" v-for="item in skuInfo.skuSaleAttrValueList" :key="item.id">{{ item.saleAttrName }}</el-tag>
</el-col>
</el-row>
<el-row style="margin: 10px 0">
<el-col :span="6">商品图片:</el-col>
<el-col :span="18">
<el-carousel :interval="4000" type="card" height="200px" >
<el-carousel-item v-for="item in skuInfo.skuImageList" :key="item.id">
<img :src="item.imgUrl" alt="" style="width: 100%;height:100%">
</el-carousel-item>
</el-carousel>
</el-col>
</el-row>
</template>
</el-drawer>
轮播图 carousel
注意:把对应的style也复制过来
4.3 商品详情展示业务
API src\api\product\sku\index.ts
//获取商品详情的接口
SKUINFO_URL = '/admin/product/getSkuInfo/',
//获取商品详情的接口
export const reqSkuInfo = (skuId: number) => {
return request.get<any, SkuInfoData>(API.SKUINFO_URL + skuId)
}
ts类型
//获取SKU商品详情接口的ts类型
export interface SkuInfoData extends ResponseData {
data: SkuData
}
4.4 发请求&&存储数据
let skuInfo = ref<any>({})
//查看商品详情按钮的回调
const findSku = async (row: SkuData) => {
//抽屉展示出来
drawer.value = true
//获取已有商品详情数据
let result: SkuInfoData = await reqSkuInfo(row.id as number)
//存储已有的SKU
skuInfo.value = result.data
}
4.5 展示数据(销售属性为例)
五、 删除SKU
API
//删除SKU的接口
DELETESKU_URL = 'http://114.115.179.162:8022/prod-api/admin/product/deleteSku/',
//删除SKU的接口
export const reqRemoveSku = (skuId: number) =>{
return request.delete<any, any>(API.DELETESKU_URL + skuId)
}
//删除SKU的回调
const deleSku = async(row:SkuData)=>{
let result:any = await reqRemoveSku(row.id as number)
if(result.code == 200){
ElMessage({
type:'success',
message:'删除成功'
})
getHasSku()
}else{
ElMessage({
type:'error',
message:'删除失败'
})
}
}
六、结论
全部代码
src\views\product\sku\index.vue
<template>
<el-card>
<el-table border :data="skuArr">
<el-table-column
type="index"
align="center"
width="80px"
label="序号"
></el-table-column>
<el-table-column
show-overflow-tooltip
width="150px"
label="名称"
prop="skuName"
></el-table-column>
<el-table-column
show-overflow-tooltip
width="150px"
label="描述"
prop="skuDesc"
></el-table-column>
<el-table-column width="150px" label="图片">
<!-- img需要用插槽 -->
<template #="{ row, $index }">
<img :src="row.skuDefaultImg" alt="" style="width: 80px; height: 80px" />
</template>
</el-table-column>
<el-table-column width="150px" label="重量" prop="weight"></el-table-column>
<el-table-column width="150px" label="价格" prop="price"></el-table-column>
<el-table-column width="250px" label="操作" fixed="right">
<template #="{ row, $index }">
<el-button
type="default"
size="small"
:icon="row.isSale == 1 ? 'Bottom' : 'Top'"
@click="updateSale(row)"
></el-button>
<el-button
type="primary"
size="small"
icon="Edit"
@click="updateSku"
></el-button>
<el-button
type="info"
size="small"
icon="InfoFilled"
@click="findSku(row)"
></el-button>
<el-button type="danger" size="small" icon="Delete" @click="deleSku(row)"></el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
v-model:current-page="pageNo"
v-model:page-size="pageSize"
:page-sizes="[10, 20, 30, 40]"
:background="true"
layout=" prev, pager, next, jumper,->, sizes,total"
:total="total"
@size-change="sizeChange"
@current-change="getHasSku"
/>
</el-card>
<el-drawer v-model="drawer" >
<template #header>
<h4>商品详情</h4>
</template>
<template #default>
<el-row style="margin: 10px 0">
<el-col :span="6">名称:</el-col>
<el-col :span="18">{{ skuInfo.skuName }}</el-col>
</el-row>
<el-row style="margin: 10px 0">
<el-col :span="6">描述:</el-col>
<el-col :span="18">{{ skuInfo.skuDesc }}</el-col>
</el-row>
<el-row style="margin: 10px 0">
<el-col :span="6">价格(元):</el-col>
<el-col :span="18">{{ skuInfo.price}}</el-col>
</el-row>
<el-row style="margin: 10px 0">
<el-col :span="6">平台属性:</el-col>
<el-col :span="18">
<el-tag style="margin: 2px" v-for="item in skuInfo.skuAttrValueList" :key="item.id">{{ item.attrName }}</el-tag>
</el-col>
</el-row>
<el-row style="margin: 10px 0">
<el-col :span="6">销售属性:</el-col>
<el-col :span="18">
<el-tag type="danger" style="margin: 2px" v-for="item in skuInfo.skuSaleAttrValueList" :key="item.id">{{ item.saleAttrName }}</el-tag>
</el-col>
</el-row>
<el-row style="margin: 10px 0">
<el-col :span="6">商品图片:</el-col>
<el-col :span="18">
<el-carousel :interval="4000" type="card" height="200px" >
<el-carousel-item v-for="item in skuInfo.skuImageList" :key="item.id">
<img :src="item.imgUrl" alt="" style="width: 100%;height:100%">
</el-carousel-item>
</el-carousel>
</el-col>
</el-row>
</template>
</el-drawer>
</template>
<script setup lang="ts">
import { ref, onMounted } from "vue";
import { reqSkuList, reqCancelSale, reqSaleSku,reqSkuInfo,reqRemoveSku } from "@/api/product/sku/index.ts";
import type { SkuResponseData, SkuData ,SkuInfoData} from "@/api/product/sku/type.ts";
import { ElMessage } from "element-plus";
//当前页码
let pageNo = ref<number>(1);
//每一页展示的数据
let pageSize = ref<number>(10);
//存储已有品牌数据总数
let total = ref<number>(0);
//存储已有sku的数据
let skuArr = ref<SkuData[]>([]);
//控制抽屉显示与隐藏的字段
let drawer = ref<boolean>(false);
//存储商品详情信息
let skuInfo = ref<any>({})
const getHasSku = async (pager = 1) => {
//修改当前页码
pageNo.value = pager;
let result: SkuResponseData = await reqSkuList(pageNo.value, pageSize.value);
console.log(result);
if (result.code == 200) {
skuArr.value = result.data.records;
total.value = result.data.total;
}
};
//组件挂载完毕钩子---发一次请求,获取第一页、一页三个已有品牌数据
onMounted(() => {
getHasSku();
});
//当下拉菜单发生变化的时候触发此方法
//这个自定义事件,分页器组件会将下拉菜单选中数据返回
const sizeChange = () => {
//当前每一页的数据量发生变化的时候,当前页码归1
getHasSku();
};
//商品的上架与下架的操作
const updateSale = async (row: SkuData) => {
//如果当前商品的isSale==1,说明当前商品是上架的额状态->更新为下架
//否则else情况与上面情况相反
if (row.isSale == 1) {
//下架操作
await reqCancelSale(row.id as number);
//提示信息
ElMessage({ type: "success", message: "下架成功" });
//发请求获取当前更新完毕的全部已有的SKU
getHasSku(pageNo.value);
} else {
//下架操作
await reqSaleSku(row.id as number);
//提示信息
ElMessage({ type: "success", message: "上架成功" });
//发请求获取当前更新完毕的全部已有的SKU
getHasSku(pageNo.value);
}
};
//更新已有的SKU
const updateSku = () => {
ElMessage({
type: "success",
message: "keson正在努力开发中~~~",
});
};
//查看商品详情按钮的回调
const findSku = async (row: SkuData) => {
//显示抽屉
drawer.value = true;
//获取已有的商品详情数据
let result:SkuInfoData =await reqSkuInfo(row.id as number)
console.log(result)
//存储已有的SKU
skuInfo.value = result.data
};
//删除SKU的回调
const deleSku = async(row:SkuData)=>{
let result:any = await reqRemoveSku(row.id as number)
if(result.code == 200){
ElMessage({
type:'success',
message:'删除成功'
})
getHasSku()
}else{
ElMessage({
type:'error',
message:'删除失败'
})
}
}
</script>
<style scoped lang="scss">
.el-card {
margin: 20px 0;
}
.el-table {
margin: 10px 0;
}
.el-carousel__item img {
color: #475669;
opacity: 0.75;
line-height: 200px;
margin: 0;
text-align: center;
}
.el-carousel__item:nth-child(2n) {
background-color: #99a9bf;
}
.el-carousel__item:nth-child(2n + 1) {
background-color: #d3dce6;
}
</style>
这模块的思路其实都比较简单。无外乎API(type),组件内发请求拿数据、将数据放到模板中。再加上一个对仓库的处理。
这部分真正的难点也是最值得学习的点在于
1:type的书写
2:对数据结构的理解(可以将请求回来的数据放到正确的位置上)
3:element-plus组件的使用。