练手项目1笔记 day06

目标

  • 完成选择商品分类功能
  • 完成品牌选择功能
  • 完成扩展属性功能
  • 完成规格选择功能
  • 完成SKU商品信息功能
  • 完成是否启用规格功能

1. 商品录入【选择商品分类】

1. 需求分析

实现效果为商品分类右边显示三级效果

当用户选择一级分类后,二级分类对应更新,当用户选择二级分类后,三级分类要对应更新

2. 准备

shop-web工程创建ItemCatController,拷贝运营商部分的代码即可

创建item_catService.js,拷贝运营商部分的代码

修改goodsController.js,引入itemCatService

修改goods_edit.html,添加引用

<script src="../plugins/angularjs/angular.min.js"></script>
<script type="text/javascript" src="../js/base.js"></script>
<script type="text/javascript" src="../js/service/goodsService.js"></script>
<script type="text/javascript" src="../js/service/uploadService.js"></script>
<script type="text/javascript" src="../js/service/itemCatService.js"></script>
<script type="text/javascript" src="../js/controller/goodsController.js"></script>
<script type="text/javascript" src="../js/controller/baseController.js"></script>

3. 代码实现

1. 一级分类下拉选择框

在goodsController增加代码

// 查询商品一级分类
$scope.selectItemCat1List = function () {
  itemCatService.findByParentId(0).success(
    function (response) {
      $scope.itemCat1List = response;
    }
  );
}

页面调用该方法

<body class="hold-transition skin-red sidebar-mini" ng-app="pinyougou" ng-controller="goodsController" ng-init="selectItemCat1List()>

修改goods_edit.html一级分类下拉选择框

<select class="form-control" ng-model="entity.goods.category1Id"
        ng-options="item.id as item.name for item in itemCat1List">
</select>

ng-options属性可以在表达式中使用数组或对象来自动生成一个select中的option列表。ng-options与ng-repeat很相似,很多时候可以用ng-repeat来代替ng-options。但是ng-options提供了一些好处,例如减少内存提高速度,以及提供选择框的选项来让用户选择。

2. 二级分类下拉选择框

在goodsController增加代码

// 查询二级分类
$scope.$watch('entity.goods.category1Id',function (newValue, oldValue) {
  itemCatService.findByParentId(newValue).success(
    function (response) {
      $scope.itemCat2List = response;
    }
  );
})

$watch方法用于监控某个变量的值,当被监控的值发生变化,自动执行相应的函数

修改goods_edit.html的二级分类下拉框

<select class="form-control select-sm"  ng-model="entity.goods.category2Id"
        ng-options="item.id as item.name for item in itemCat2List"></select>
3. 三级分类下拉选择框

在goodsController中增加代码

// 查询三级分类
$scope.$watch('entity.goods.category2Id',function (newValue, oldValue) {
  itemCatService.findByParentId(newValue).success(
    function (response) {
      $scope.itemCat3List = response;
    }
  );
})

修改goods_edit.html中三级分类下拉框

<select class="form-control select-sm"  ng-model="entity.goods.category3Id"
        ng-options="item.id as item.name for item in itemCat3List"></select>
4. 读取模板id

在goodsController增加代码

// 查询三级分类
$scope.$watch('entity.goods.category3Id',function (newValue, oldValue) {
  itemCatService.findOne(newValue).success(
    function (response) {
      $scope.entity.goods.typeTemplateId = response.typeId;
    }
  );
})

在goods_edit.html显示模板id

模板ID:{{entity.goods.typeTemplateId}}

2. 商品录入【品牌选择】

1. 需求分析

用户选择商品分类后,品牌列表根据用户选择的分类进行更新。具体逻辑为:根据用户选择的三级分类找到对应的商品类型模板,商品类型模板中存储品牌的列表json数据。

2. 代码实现

1. shop-web工程创建TypeTemplateController

从运营商部分拷贝

2. shop-web工程创建typeTemplateService.js

从运营商部分拷贝

3. 在goodsController引入typeTemplateService,新增代码
// 模板id选择后,更新品牌列表
$scope.$watch('entity.goods.typeTemplateId',function (newValue, oldValue) {
  typeTemplateService.findOne(newValue).success(
    function (response) {
      $scope.typeTemplate = response;//根据模板id获取类型模板
      $scope.typeTemplate.brandIds = JSON.parse($scope.typeTemplate.brandIds);//字符串转换为json集合
    }
  );
})

在页面goods_edit.html引入js

<script type="text/javascript" src="../js/service/typeTemplateService.js"></script>

添加品牌选择框

<div class="col-md-2 title">品牌</div>
<div class="col-md-10 data">
  <select class="form-control"  ng-model="entity.goods.brandId"
          ng-options="brand.id as brand.text for brand in typeTemplate.brandIds"></select>
</div>

注意:如果选项更改为brand,要保持brand的属性id text跟数据库保持一致。

3. 商品录入【扩展属性】

1. 需求分析

实现扩展属性的录入

2. 代码实现

修改goodsController.js,在用户更新模板id时,读取模板中的扩展属性赋给商品的扩展属性

// 模板id选择后,更新品牌列表
$scope.$watch('entity.goods.typeTemplateId',function (newValue, oldValue) {
  typeTemplateService.findOne(newValue).success(
    function (response) {
      $scope.typeTemplate = response;//根据模板id获取类型模板
      $scope.typeTemplate.brandIds = JSON.parse($scope.typeTemplate.brandIds);//字符串转换为json集合
      $scope.entity.goodsDesc.customAttributeItems = JSON.parse($scope.typeTemplate.customAttributeItems);
    }
  );
})

修改goods_edit.html

<!--扩展属性-->
<div class="tab-pane" id="customAttribute">
  <div class="row data-type">
    <div ng-repeat="item in entity.goodsDesc.customAttributeItems">
      <div class="col-md-2 title">{{item.text}}</div>
      <div class="col-md-10 data">
        <input class="form-control" placeholder="{{item.text}}" ng-model="item.value">
      </div>
    </div>       
  </div>
</div>

4. 商品录入【规格选择】

1. 需求分析

显示规格及选项列表(复选框),并保存用户选择的结果

在这里插入图片描述

从模板中提取规格列表

[{"id":27,"text":"网络"},{"id":32,"text":"机身内存"}]

得到List<Map>,遍历

通过id查询规格选项列表

[{"id":27,"text":"网络",options:[{},{}]},{"id":32,"text":"机身内存",options:[{},{}]}]

2. 显示规格选项列表

模板中只记录了规格名称,也需要显示规格的规格选项。

1. sellergoods-interface的TypeTemplateService.java新增方法定义
// 返回规格列表
public List<Map> findSpecList(Long id);
2. sellergoods-service的TypeTemplateServiceImpl.java新增方法
@Autowired
	private TbSpecificationOptionMapper specificationOptionMapper;

	@Override
	public List<Map> findSpecList(Long id) {
		// 查询模板
		TbTypeTemplate typeTemplate = typeTemplateMapper.selectByPrimaryKey(id);
		List<Map> list = JSON.parseArray(typeTemplate.getSpecIds(), Map.class);
		for (Map map : list) {
			// 查询规格选项列表
			TbSpecificationOptionExample example = new TbSpecificationOptionExample();
			TbSpecificationOptionExample.Criteria criteria = example.createCriteria();
			criteria.andSpecIdEqualTo(new Long((Integer)map.get("id")));
			List<TbSpecificationOption> options = specificationOptionMapper.selectByExample(example);
			map.put("options",options);
		}
		return list;
	}

最难理解的就是类型转换部分,是否是根据id得到的就是integer类型?强转只是为了确保是integer,然后再转换为long类型?

3. 在shop-web的TypeTemplateController.java新增方法
@RequestMapping("/findSpecList")
	public List<Map> findSpecList(Long id){
		return typeTemplateService.findSpecList(id);
	}
4. 测试后端代码

通过

5. 前端

修改shop-web的typeTemplateService.js

// 查询规格列表
this.findSpecList = function (id) {
  return $http.get('../typeTemplate/findSpecList.do?id='+id);
}

修改shop-web的goodsController.js

// $scope.specList = ["options":[]];	
// 模板id选择后,更新品牌列表 扩展属性 规格列表
$scope.$watch('entity.goods.typeTemplateId',function (newValue, oldValue) {
  typeTemplateService.findOne(newValue).success(
    function (response) {
      $scope.typeTemplate = response;//根据模板id获取类型模板
      $scope.typeTemplate.brandIds = JSON.parse($scope.typeTemplate.brandIds);//字符串转换为json集合
      $scope.entity.goodsDesc.customAttributeItems = JSON.parse($scope.typeTemplate.customAttributeItems);
    }
  );
  // 查询规格列表
  typeTemplateService.findSpecList(newValue).success(
    function (response) {

      $scope.specList = response;
      $scope.specList = JSON.parse($scope.specList);
      alert($scope.specList);
    }
  );
})

小插曲:之前没成功,先alert,发现undefined,想着是不是没设置好初始的格式,并alert,发现更不靠谱了,想着是不是没有将字符串转json,果真,就显示规格选项成功了。

修改goods_edit.html页面

<div class="row data-type">

  <div ng-repeat="pojo in specList">
    <div class="col-md-2 title">{{pojo.text}}</div>
    <div class="col-md-10 data">

      <span ng-repeat="option in pojo.options">
        <input  type="checkbox" >{{option.optionName}}
      </span>  	
    </div>
  </div>   
</div>

3. 规格选项的保存(难点)

1. 需求分析

需要将用户选中的选项保存在tb_goods_desc表中的specification_items字段中,定义json格式如下

[{"attributeName":"网络","attributeValue":["移动3G","移动4G"]},{"attributeName":"机身内存","attributeValue":["16G","32G"]}]

记录的就是勾选的结果。attributeName就是规格的名称,attributeValue就是勾选的规格的选项。

思路分析:

最终要存到entity.goodsDesc.specificationItems=[],push往里面加

得到entity.goodsDesc.specificationItems=[{"attributeName":"网络","attributeValue":["移动3G","移动4G"]}]

存在两种情况:

  1. 选择的选项,规格名称已经存在
  2. 选择的选项,规格名称不存在

判断集合中attributeName的值有没有当前我要添加的选项的规格名称,集合需要遍历

编写通用方法,在集合中查询对象中某个属性值是否存在,查到返回对象,查不到null

2. 代码

在baseController.js增加代码

 // 从集合中按照key查询对象
    $scope.searchObjectByKey = function (list, key, keyValue) {
        for(var i=0;i<list.length;i++){
            if(list[i][key]===keyValue){//存在这个键值对 list[i]每个元素
                return list[i];
            }
        }
        return null;
    }

在goodsController.js增加代码

 // 类似于删除的时候勾选的复选框,操作之前要初始化结构
    $scope.updateSpecAttribute = function ($event, name, value) {//要传的参数:网络、勾选的移动3G
	    // 看该attributeName是否存在
        var object = $scope.searchObjectByKey($scope.entity.goodsDesc.specificationItems,'attributeName',name);
        // 需要追加attributeValue
        if(object!=null){
            if($event.target.checked){
                alert("123");
                object.attributeValue.push(value);// 追加到attributeValue的变量中
            }else{
                // 取消勾选
                object.attributeValue.splice(object.attributeValue.indexOf(value),1);//移除选项
                // 如果选项都取消了,将此条记录移除
                if(object.attributeValue.length===0){
                    $scope.entity.goodsDesc.specificationItems.splice(
                        $scope.entity.goodsDesc.specificationItems.indexOf(object),1
                    )
                }
            }
        }else{
            // attributeName不存在,添加整个结构
            $scope.entity.goodsDesc.specificationItems.push(
                {"attributeName":name,"attributeValue":[value]}
            )
        }
    }

另外需要初始化specificationItems

$scope.entity={goodsDesc:{itemImages:[],specificationItems:[]}};

在goods_edit.html调用该方法

<div class="row data-type">

  <div ng-repeat="pojo in specList">
    <div class="col-md-2 title">{{pojo.text}}</div>
    <div class="col-md-10 data">

      <span ng-repeat="option in pojo.options">
        <input  type="checkbox" ng-click="updateSpecAttribute($event,pojo.text,option.optionName)">{{option.optionName}}
      </span>  	
    </div>
  </div>   
</div>

可以再页面上某个区域临时添加表达式,观察测试结果

{{entity.goodsDesc.specificationItems}}

4. 商品录入【SKU商品信息】

1. 需求分析

基于上一步完成的规格选择,根据选择的规格录入商品的SKU信息。当用户选择相应的规格,下面的SKU列表会自动生成。

实现思路:

  1. 定义一个初始的不带规格名称的集合,只有一条记录。
  2. 循环用户选择的规格,根据规格名称和已选择的规格选项对原集合扩充,添加规格名称和值。新增的记录数和选择的规格选项个数相同。

在这里插入图片描述

如何实现?

采用克隆

浅克隆 var a={} b=a;

深克隆 var a={‘name’:‘abc’} var b={‘name’:‘abc’}

技巧:var b = JSON.parse(JSON.stringify(a))

2. 前端
1. 生成SKU列表(深克隆)

在goodsController.js实现创建sku列表的方法

    // 创建SKU列表
    $scope.createItemList = function () {
	    // 初始化itemList,将spec,price,num,status,isDefault这些属性放进去
        $scope.entity.itemList = [{spec:{},price:0,num:9999,status:"0",isDefault:"0"}];
        // 简化spec
        var items = $scope.entity.goodsDesc.specificationItems;
        for(var i=0;i<items.length;i++){
            // 驴打滚,每次itemList都更新过了
            $scope.entity.itemList = addColumn($scope.entity.itemList,items[i].attributeName,items[i].attributeValue);
        }
    }

    // 增加列的方法,参数列名称,列的值
    addColumn=function (list, columnName, columnValues) {
        var newList = [];//新集合
        for(var i=0;i<list.length;i++){
            var oldRow = list[i];//之前的行
            for(var j=0;j<columnValues.length;j++){
                var newRow = JSON.parse(JSON.stringify(oldRow));//对原来的行深克隆
                newRow.spec[columnName] = columnValues[j];
                newList.push(newRow);
            }
        }
        return newList;
    }
  1. 在更新规格属性后调用生成sku列表的方法
<input  type="checkbox" ng-click="updateSpecAttribute($event,pojo.text,option.optionName);createItemList()">{{option.optionName}}
  1. 在页面添加表达式,测试
{{entity.itemList}}

显示点击出来的列表

2. 显示SKU列表

goods_edit.html绑定SKU列表

<table class="table table-bordered table-striped table-hover dataTable">
  <thead>
    <tr>					                          
      <th class="sorting" ng-repeat="item in entity.goodsDesc.specificationItems">{{item.attributeName}}</th>

      <th class="sorting">价格</th>
      <th class="sorting">库存</th>
      <th class="sorting">是否启用</th>
      <th class="sorting">是否默认</th>
    </tr>
  </thead>
  <tbody>
    <!--$scope.entity.itemList = [{spec:{},price:0,num:9999,status:"0",isDefault:"0"}];-->
    <tr ng-repeat="pojo in entity.itemList">
      <!--和上面attributeName的一样-->
      <td ng-repeat="item in entity.goodsDesc.specificationItems">
        {{pojo.spec[item.attributeName]}}
      </td>
      <td>
        <input class="form-control" ng-model="pojo.price" placeholder="价格">
      </td>
      <td>
        <input class="form-control" ng-model="pojo.num" placeholder="库存数量">
      </td>
      <td>
        <input type="checkbox" ng-model="pojo.status" ng-true-value="1" ng-false-value="0">
      </td>
      <td>
        <input type="checkbox"  ng-model="pojo.isDefault" ng-true-value="1" ng-false-value="0">
      </td>
    </tr>

  </tbody>
</table>

删除测试表达式

3. 后端

比较麻烦,但是理解很简单,就是给serviceImpl的GoodsServiceImpl.java的add方法添加itemList

@Autowired
private TbGoodsDescMapper goodsDescMapper;

@Autowired
private TbBrandMapper brandMapper;

@Autowired
private TbItemCatMapper itemCatMapper;

@Autowired
private TbSellerMapper sellerMapper;

@Autowired
private TbItemMapper itemMapper;
/**
	 * 增加
	 */
@Override
public void add(Goods goods) {
  goods.getGoods().setAuditStatus("0");//设置未申请状态
  goodsMapper.insert(goods.getGoods());
  goods.getGoodsDesc().setGoodsId(goods.getGoods().getId());//设置id
  goodsDescMapper.insert(goods.getGoodsDesc());//插入商品细节数据

  // itemList
  for (TbItem item : goods.getItemList()) {
    // title eg.苹果(Apple) iPhone 4s 8GB 黑色 联通3G手机
    String title = goods.getGoods().getGoodsName();//商品名
    // {"机身内存":"16G","网络":"联通3G"}
    Map<String,Object> specMap =JSON.parseObject(item.getSpec());
    for (String key : specMap.keySet()) {
      title += " "+specMap.get(key);//完善title
    }
    item.setTitle(title);
    item.setGoodsId(goods.getGoods().getId());
    item.setSellerId(goods.getGoods().getSellerId());
    item.setCategoryid(goods.getGoods().getCategory3Id());
    item.setCreateTime(new Date());
    item.setUpdateTime(new Date());

    // 品牌名称
    TbBrand brand = brandMapper.selectByPrimaryKey(goods.getGoods().getBrandId());
    item.setBrand(brand.getName());
    // 分类名称
    TbItemCat itemCat = itemCatMapper.selectByPrimaryKey(goods.getGoods().getCategory3Id());
    item.setCategory(itemCat.getName());
    //商家名称
    TbSeller seller = sellerMapper.selectByPrimaryKey(goods.getGoods().getSellerId());
    item.setSeller(seller.getNickName());
    // 图片地址(取SPU的第一个图片)
    // eg.[{"color":"白色","url":"http://192.168.25.133/group1/M00/00/00/wKgZhVmNXEWAWuHOAAjlKdWCzvg949.jpg"},{"color":"黑色","url":"http://192.168.25.133/group1/M00/00/00/wKgZhVmNXEuAB_ujAAETwD7A1Is158.jpg"},{"color":"蓝色","url":"http://192.168.25.133/group1/M00/00/00/wKgZhVmNXFWANtjTAAFa4hmtWek619.jpg"}]
    List<Map> imageList =JSON.parseArray(goods.getGoodsDesc().getItemImages(),Map.class);
    if(imageList.size()>0){
      item.setImage((String)imageList.get(0).get("url"));
    }
    itemMapper.insert(item);
  }
}

5. 商品录入【是否启用规格】

1. 需求分析

在规格面板添加是否启用规格,用户没有选择该项时,将原来的规格面板和SKU列表隐藏,保存商品后只生成一个SKU

2. 前端代码

goods_add.html添加复选框,用if指令控制规格面板和SKU列表的显示和隐藏

<div class="tab-pane" id="spec">
  <div class="row data-type">
    <div class="col-md-2 title">是否启用规格</div>
    <div class="col-md-10 data">
      <input type="checkbox" ng-model="entity.goods.isEnableSpec" ng-true-value="1" ng-false-value="0">
    </div>
  </div>
</div>

3. 后端代码

修改GoodsServiceImpl的add方法

@Autowired
	private TbGoodsDescMapper goodsDescMapper;

	@Autowired
	private TbBrandMapper brandMapper;

	@Autowired
	private TbItemCatMapper itemCatMapper;

	@Autowired
	private TbSellerMapper sellerMapper;

	@Autowired
	private TbItemMapper itemMapper;
	/**
	 * 增加
	 */
	@Override
	public void add(Goods goods) {
		goods.getGoods().setAuditStatus("0");//设置未申请状态
		goodsMapper.insert(goods.getGoods());
		goods.getGoodsDesc().setGoodsId(goods.getGoods().getId());//设置id
		goodsDescMapper.insert(goods.getGoodsDesc());//插入商品细节数据

		if("1".equals(goods.getGoods().getIsEnableSpec())){
			// itemList
			for (TbItem item : goods.getItemList()) {
				// title eg.苹果(Apple) iPhone 4s 8GB 黑色 联通3G手机
				String title = goods.getGoods().getGoodsName();//商品名
				// {"机身内存":"16G","网络":"联通3G"}
				Map<String,Object> specMap =JSON.parseObject(item.getSpec());
				for (String key : specMap.keySet()) {
					title += " "+specMap.get(key);//完善title
				}
				item.setTitle(title);
				setItemValues(item,goods);
				itemMapper.insert(item);
			}
		}else{
			TbItem item = new TbItem();
			item.setTitle(goods.getGoods().getGoodsName());
			item.setPrice(goods.getGoods().getPrice());
			item.setStatus("1");//状态
			item.setIsDefault("1");//是否默认
			item.setNum(9999);//库存数量
			item.setSpec("{}");
			setItemValues(item,goods);
			itemMapper.insert(item);
		}

	}

	private void setItemValues(TbItem item,Goods goods){
		item.setGoodsId(goods.getGoods().getId());//SPU编号
		item.setSellerId(goods.getGoods().getSellerId());//商家编号
		item.setCategoryid(goods.getGoods().getCategory3Id());//商家分类编号(3级)
		item.setCreateTime(new Date());//创建日期
		item.setUpdateTime(new Date());//修改日期

		// 品牌名称
		TbBrand brand = brandMapper.selectByPrimaryKey(goods.getGoods().getBrandId());
		item.setBrand(brand.getName());
		// 分类名称
		TbItemCat itemCat = itemCatMapper.selectByPrimaryKey(goods.getGoods().getCategory3Id());
		item.setCategory(itemCat.getName());
		//商家名称
		TbSeller seller = sellerMapper.selectByPrimaryKey(goods.getGoods().getSellerId());
		item.setSeller(seller.getNickName());
		// 图片地址(取SPU的第一个图片)
		// eg.[{"color":"白色","url":"http://192.168.25.133/group1/M00/00/00/wKgZhVmNXEWAWuHOAAjlKdWCzvg949.jpg"},{"color":"黑色","url":"http://192.168.25.133/group1/M00/00/00/wKgZhVmNXEuAB_ujAAETwD7A1Is158.jpg"},{"color":"蓝色","url":"http://192.168.25.133/group1/M00/00/00/wKgZhVmNXFWANtjTAAFa4hmtWek619.jpg"}]
		List<Map> imageList =JSON.parseArray(goods.getGoodsDesc().getItemImages(),Map.class);
		if(imageList.size()>0){
			item.setImage((String)imageList.get(0).get("url"));
		}
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值