基础概念
SPU
Standard Product Unit 标准化产品单元:是商品信息聚合的最小单位,是一组可复用、易检索的标准化信息的集合,该集合描述了一个产品的特性。
SPU: Standard Product Unit
(标准产品单位)
- SPU 是商品信息聚合的最小单位,是一组可复用、易检索的标准化信息的集合,该集合描述了一个产品的特性。
- 通俗点讲,属性值、特性相同的商品就可以称为一个 SPU。
- 例如:
iPhone 12
就是一个 SPU,与商家,与颜色、款式、套餐都无关。
SKU
Stock Keeping Unit 库存量单位:即库存进出计量的基本单元,可以是以件、盒等为单位。SKU这是对于大型连锁超市 DC (配送中心)物流管理的一个必要的方法。现在已经被引申为产品统一编号的简称,每种产品均对应有唯一的SKU号。
SKU: Stock Keeping Unit
(库存量单位)
- SKU 即库存进出计量的单位, 可以是以件、盒、托盘等为单位。
- SKU 是物理上不可分割的最小存货单元。在使用时要根据不同业态,不同管理模式来处理。
- 在服装、鞋类商品中使用最多最普遍。
- 例如:
iPhone 12
的颜色(深空灰等),存储容量(64GB 256GB)。
举例区分
iPhoneX 是 SPU、MI8 是 SPU
iPhoneX 64G 黑曜石是 SKU
MI8 8+64G 黑色是 SKU
基础属性【规格参数】与销售属性
每个分类下的商品共享规格参数与销售属性。知识有些商品不一定要用这个分类下全部的属性。
- 属性是以三级分类组织起来的;
- 规格参数中有些是可以提供检索的;
- 规格参数也是基本属性,他们具有自己的分组;
- 属性的分组也是以三级分类组织起来的;
- 属性名是确定的,但是值是每一个商品不同决定的;
商品的基础属性是SPU的特性,商品的销售属性是SKU的特性。
前端组件抽取
树形列表
src\views\modules\common\category.vue
<!-- 树形列表 -->
<template>
<el-tree
:data="categoryList"
:props="defaultProps"
node-key="catId"
></el-tree>
</template>
<script>
//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
//例如:import 《组件名称》 from '《组件路径》';
export default {
//import引入的组件需要注入到对象中才能使用
components: {},
data() {
//这里存放数据
return {
categoryList: [],
defaultProps: {
// 此处设置子级分类,及其属性名
children: 'childrenList',
label: 'name',
},
}
},
//监听属性 类似于data概念
computed: {},
//监控data中的数据变化
watch: {},
//方法集合
methods: {
getCategoryList() {
this.$http({
url: this.$http.adornUrl('/product/category/list/tree'),
method: 'get',
}).then(({ data }) => {
this.categoryList = data.data
})
},
},
//生命周期 - 创建完成(可以访问当前this实例)
created() {
this.getCategoryList()
},
//生命周期 - 挂载完成(可以访问DOM元素)
mounted() {},
beforeCreate() {}, //生命周期 - 创建之前
beforeMount() {}, //生命周期 - 挂载之前
beforeUpdate() {}, //生命周期 - 更新之前
updated() {}, //生命周期 - 更新之后
beforeDestroy() {}, //生命周期 - 销毁之前
destroyed() {}, //生命周期 - 销毁完成
activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
}
</script>
<style scoped>
</style>
属性分组
src\views\modules\product\attrgroup.vue
<!-- 属性分组 -->
<template>
<el-row :gutter="20">
<el-col :span="6">
<!-- 分类列表 -->
<category></category>
</el-col>
<el-col :span="18">
<!-- 表格 -->
<div class="mod-config">
<el-form
:inline="true"
:model="dataForm"
@keyup.enter.native="getDataList()"
>
<el-form-item>
<el-input
v-model="dataForm.key"
placeholder="参数名"
clearable
></el-input>
</el-form-item>
<el-form-item>
<el-button @click="getDataList()">查询</el-button>
<el-button
v-if="isAuth('product:attrgroup:save')"
type="primary"
@click="addOrUpdateHandle()"
>
新增
</el-button>
<el-button
v-if="isAuth('product:attrgroup:delete')"
type="danger"
@click="deleteHandle()"
:disabled="dataListSelections.length <= 0"
>
批量删除
</el-button>
</el-form-item>
</el-form>
<el-table
:data="dataList"
border
v-loading="dataListLoading"
@selection-change="selectionChangeHandle"
style="width: 100%"
>
<el-table-column
type="selection"
header-align="center"
align="center"
width="50"
></el-table-column>
<el-table-column
prop="attrGroupId"
header-align="center"
align="center"
label="分组id"
></el-table-column>
<el-table-column
prop="attrGroupName"
header-align="center"
align="center"
label="组名"
></el-table-column>
<el-table-column
prop="sort"
header-align="center"
align="center"
label="排序"
></el-table-column>
<el-table-column
prop="descript"
header-align="center"
align="center"
label="描述"
></el-table-column>
<el-table-column
prop="icon"
header-align="center"
align="center"
label="组图标"
></el-table-column>
<el-table-column
prop="catelogId"
header-align="center"
align="center"
label="所属分类id"
></el-table-column>
<el-table-column
fixed="right"
header-align="center"
align="center"
width="150"
label="操作"
>
<template slot-scope="scope">
<el-button
type="text"
size="small"
@click="addOrUpdateHandle(scope.row.attrGroupId)"
>
修改
</el-button>
<el-button
type="text"
size="small"
@click="deleteHandle(scope.row.attrGroupId)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
@size-change="sizeChangeHandle"
@current-change="currentChangeHandle"
:current-page="pageIndex"
:page-sizes="[10, 20, 50, 100]"
:page-size="pageSize"
:total="totalPage"
layout="total, sizes, prev, pager, next, jumper"
></el-pagination>
<!-- 弹窗, 新增 / 修改 -->
<add-or-update
v-if="addOrUpdateVisible"
ref="addOrUpdate"
@refreshDataList="getDataList"
></add-or-update>
</div>
</el-col>
</el-row>
</template>
<script>
//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
//例如:import 《组件名称》 from '《组件路径》';
import Category from '../common/category'
import AddOrUpdate from './attrgroup-add-or-update'
export default {
//import引入的组件需要注入到对象中才能使用
components: { Category,AddOrUpdate },
data() {
return {
dataForm: {
key: '',
},
dataList: [],
pageIndex: 1,
pageSize: 10,
totalPage: 0,
dataListLoading: false,
dataListSelections: [],
addOrUpdateVisible: false,
}
},
activated() {
this.getDataList()
},
methods: {
// 获取数据列表
getDataList() {
this.dataListLoading = true
this.$http({
url: this.$http.adornUrl('/product/attrgroup/list'),
method: 'get',
params: this.$http.adornParams({
page: this.pageIndex,
limit: this.pageSize,
key: this.dataForm.key,
}),
}).then(({ data }) => {
if (data && data.code === 0) {
this.dataList = data.page.list
this.totalPage = data.page.totalCount
} else {
this.dataList = []
this.totalPage = 0
}
this.dataListLoading = false
})
},
// 每页数
sizeChangeHandle(val) {
this.pageSize = val
this.pageIndex = 1
this.getDataList()
},
// 当前页
currentChangeHandle(val) {
this.pageIndex = val
this.getDataList()
},
// 多选
selectionChangeHandle(val) {
this.dataListSelections = val
},
// 新增 / 修改
addOrUpdateHandle(id) {
this.addOrUpdateVisible = true
this.$nextTick(() => {
this.$refs.addOrUpdate.init(id)
})
},
// 删除
deleteHandle(id) {
var ids = id
? [id]
: this.dataListSelections.map((item) => {
return item.attrGroupId
})
this.$confirm(
`确定对[id=${ids.join(',')}]进行[${id ? '删除' : '批量删除'}]操作?`,
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
).then(() => {
this.$http({
url: this.$http.adornUrl('/product/attrgroup/delete'),
method: 'post',
data: this.$http.adornData(ids, false),
}).then(({ data }) => {
if (data && data.code === 0) {
this.$message({
message: '操作成功',
type: 'success',
duration: 1500,
onClose: () => {
this.getDataList()
},
})
} else {
this.$message.error(data.msg)
}
})
})
},
},
}
</script>
<style scoped>
</style>
父子组件传递数据
子组件给父组件传递数据机制
- 子组件使用事件机制给父组件传递数据
- 子组件给父组件发送一个事件,携带上数据
this.$emit('事件名', 携带的数据...)
子组件
src\views\modules\common\category.vue
template
<!-- 添加点击事件 -->
<el-tree
@node-click="nodeClick"
></el-tree>
script
methods:
// 节点点击事件
nodeClick(data, node, component) {
console.log('子组件category被点击', data, node, component)
// 子给父组件发送事件,并携带数据
this.$emit('tree-node-click', data, node, component)
},
父组件
src\views\modules\product\attrgroup.vue
template
<el-col :span="6">
<!-- 分类列表 -->
<category @tree-node-click="treeNodeClick"></category>
</el-col>
script
methods:
// 感知树节点被点击
treeNodeClick(data, node, component) {
console.log('attrgroup感知到category节点被点击', data, node, component)
console.log('刚才被点击的分类id:', data.catId)
if (node.level == 3) {
this.categoryId = data.catId
this.getData()
} else {
this.categoryId = 0
}
},
getData() {
this.getDataList(this.categoryId)
},
根据分类id查询数据
前端
src\views\modules\product\attrgroup.vue
script
methods:
后端
controller
AdminAttrGroupController.java
/**
* 根据分类id查询数据
*/
@ApiOperation("根据分类id查询数据")
@GetMapping("/list/{categoryId}")
@ApiImplicitParams({
@ApiImplicitParam(paramType = "query",name = "page",value ="当前页码",dataType ="Integer"),
@ApiImplicitParam(paramType = "query",name = "limit",value ="每页记录数",dataType ="Integer"),
@ApiImplicitParam(paramType = "query",name = "sidx",value ="排序字段",dataType ="String"),
@ApiImplicitParam(paramType = "query",name = "order",value ="排序方式",dataType ="String"),
@ApiImplicitParam(paramType = "query",name = "key",value ="条件",dataType ="String")
})
public R list(@ApiIgnore @RequestParam Map<String, Object> params, @PathVariable Long categoryId){
PageUtils page = attrGroupService.queryPage(params,categoryId);
return R.ok().put("page", page);
}
service
AttrGroupService.java
PageUtils queryPage(Map<String, Object> params, Long categoryId);
AttrGroupServiceImpl.java
@Override
public PageUtils queryPage(Map<String, Object> params, Long categoryId) {
QueryWrapper<AttrGroupEntity> queryWrapper = new QueryWrapper<>();
// 如果分类id不为0
if (categoryId != 0) {
queryWrapper.eq("category_id",categoryId);
}
String key = (String) params.get("key");
log.info("key的值{}",params.get("key"));
// 如果查询条件不为空
if (StringUtils.isNotEmpty(key)) {
queryWrapper.and(wrapper -> {
wrapper.eq("attr_group_id",key).or().like("attr_group_name",key);
});
}
IPage<AttrGroupEntity> page = this.page(
new Query<AttrGroupEntity>().getPage(params),
queryWrapper
);
return new PageUtils(page);
}