美文网首页Flutter圈子Flutter中文社区Flutter
Flutter 多规格商品选择器核心工具 SKU

Flutter 多规格商品选择器核心工具 SKU

作者: CyJay | 来源:发表于2019-03-11 11:50 被阅读214次

团队打算用Flutter 覆写项目,但是遇到了一个有点恼火的事情,以前安卓和IOS在商品的多规格选择一般都有现成的库。Flutter 由于刚兴起,这方面的库我目前还没找到,于是只能自己撸一个了。
首先看看我们某个商品数据结构:

{
  "attributes": [],
  "goods_id": 1636,
  "goods_name": "珍珠奶茶",
  "image": "http://********/static/goods_images/Rlp6d1536542627.png",
  "multi_spec": [
    {
      "image": "http://********/static/goods_images/EQqf01536544612.png",
      "product_code": "",
      "sales_amount": 45,
      "spec_info_list": [
        {
          "spec_name": "规格",
          "spec_name_id": 336,
          "spec_value": "大杯",
          "spec_value_id": 1019
        },
        {
          "spec_name": "颜色",
          "spec_name_id": 337,
          "spec_value": "红色",
          "spec_value_id": 1021
        },
        {
          "spec_name": "重量",
          "spec_name_id": 338,
          "spec_value": "半斤",
          "spec_value_id": 1023
        }
      ],
      "specification_id": 1918,
      "stock": -1,
      "unit": "杯",
      "unit_price": 7
    },
    {
      "image": "http://********/static/goods_images/Fe30S1536544637.png",
      "product_code": "",
      "sales_amount": 16,
      "spec_info_list": [
        {
          "spec_name": "规格",
          "spec_name_id": 336,
          "spec_value": "中杯",
          "spec_value_id": 1020
        },
        {
          "spec_name": "颜色",
          "spec_name_id": 337,
          "spec_value": "绿色",
          "spec_value_id": 1022
        },
        {
          "spec_name": "重量",
          "spec_name_id": 338,
          "spec_value": "一斤",
          "spec_value_id": 1024
        }
      ],
      "specification_id": 1919,
      "stock": -1,
      "unit": "杯",
      "unit_price": 6
    },
    {
      "image": "http://********/static/goods_images/Fe30S1536544637.png",
      "product_code": "",
      "sales_amount": 16,
      "spec_info_list": [
        {
          "spec_name": "规格",
          "spec_name_id": 336,
          "spec_value": "中杯",
          "spec_value_id": 1020
        },
        {
          "spec_name": "颜色",
          "spec_name_id": 337,
          "spec_value": "红色",
          "spec_value_id": 1021
        },
        {
          "spec_name": "重量",
          "spec_name_id": 338,
          "spec_value": "一斤",
          "spec_value_id": 1024
        }
      ],
      "specification_id": 1919,
      "stock": -1,
      "unit": "杯",
      "unit_price": 6
    }
  ],
  "pack_cost": 0,
  "product_code": null,
  "sales_amount": 61,
  "stock": -2,
  "unit": null,
  "unit_price": null
}

multi_spec字段下就是这商品的所有规格搭配,spec_info_list字段下为组成该搭配的各规格值。
我们给分别给规格搭配和组成规格搭配的规格值做了 model :

///商品规格搭配,对应multi_spec的元素
class ShopGoodsMultiSpec {
    String image;
    String unit;
    int specificationId;
    List<ShopGoodsMultiSpecSpecInfo> specInfoList;
    int salesAmount;
    String productCode;
    int stock;
    double unitPrice;
 ///构造函数什么的省略.....
}
///组成规格搭配的规格值,对应spec_info_list的元素
class ShopGoodsMultiSpecSpecInfo {
    int specValueId;
    int specNameId;
    String specName;
    String specValue;
    
     ///覆写下面两个方法,为了防止使同一个规格值的两个ShopGoodsMultiSpecSpecInfo对象
     ///被判断为不等,在工具中的 allSpecValue[spec_info.specName].contains(spec_info) 有用,不然会出问题
    @override
    int get hashCode => "ShopGoodsMultiSpecSpecInfo_$specValueId".hashCode;
    
    bool operator ==(o){
        ShopGoodsMultiSpecSpecInfo obj = o;
    return obj.specValueId == specValueId;
    }

///构造函数什么的省略.....
}

贴上工具代码:

class SpecSkuUtil {
  List<String> allSpecKey = [];
  Map<String, ShopGoodsMultiSpec> allSpec = {};
  Map<String, List<ShopGoodsMultiSpecSpecInfo>> allSpecValue = {};
  Map<String, int> selected = {};

  /// 实例化工具,传入所有规格搭配 list
  SpecSkuUtil(List<ShopGoodsMultiSpec> multiSpec) {
    for (ShopGoodsMultiSpec spec in multiSpec) {
      List valueIds = [];
      for (ShopGoodsMultiSpecSpecInfo spec_info in spec.specInfoList) {
        valueIds.add(spec_info.specValueId);
        if (!allSpecValue.containsKey(spec_info.specName)) {
          allSpecValue[spec_info.specName] = [spec_info];
        } else if (!allSpecValue[spec_info.specName].contains(spec_info)) {
          allSpecValue[spec_info.specName].add(spec_info);
        }
      }
      valueIds.sort((a, b) => a.compareTo(b));
      valueIds = valueIds.map((id) {
        return id.toString();
      }).toList();
      allSpec[valueIds.join("-")] = spec;
      _createCollocations(valueIds);
    }
  }

  void _createCollocations(List strList) {
    void build(List candidate, String prefix, int index) {
      if (!allSpecKey.contains(prefix)) {
        allSpecKey.add(prefix);
      }
      for (int i = index; i < candidate.length; i++) {
        List tmp = new List()..addAll(candidate);
        build(tmp, (prefix == "" ? "" : prefix + "-") + tmp.removeAt(i), i);
      }
    }

    build(strList, "", 0);
  }

  /// 返回所有{规格名:List<规格值对象>}
  Map<String, List<ShopGoodsMultiSpecSpecInfo>> getAllSpecValue() {
    return allSpecValue;
  }

  /// 设置已选中的 {规格名:规格值 id}
  void setSelectedIds(Map<String, int> selected) {
    this.selected = selected;
  }

  /// 检查某属性是否可选 {规格名:规格值 id}
  bool checkEnable(Map<String, int> candidate) {
    Map<String, int> tmpMap = Map.from(selected);
    tmpMap.addAll(candidate);
    List tmp = mapValue2List(tmpMap);
    tmp.sort((a, b) => a.compareTo(b));
    return allSpecKey.contains(tmp.join("-"));
  }

  /// 获取规格搭配对象
  ShopGoodsMultiSpec getSpec() {
    List tmp = mapValue2List(selected);
    tmp.sort((a, b) => a.compareTo(b));
    return allSpec[tmp.join("-")];
  }

  /// map的值转 list
  List mapValue2List(Map<String, int> map) {
    List tmp = new List();
    map.forEach((key, value) {
      ///至于判断不为空才加入 list,这个是看实际情况
      ///如果你的程序生成的已选中Map里面不会有 null 就可以不用判断
      if (value != null) {
        tmp.add(value);
      }
    });
    return tmp;
  }
}

核心原理就是,每个规格搭配下的规格值的任意 不重复使用元素 的无序组合 都能代表该规格搭配。
如:

a,b,c  能够生成的组合就是 [a, b, c, ab, ac, bc, abc]

那么,如果我们把每个规格搭配下的规格值的任意不重复使用元素的无序组合都收集在一个list (这里叫它allSpecKey) 中,我们在校验某个规格值是否可选时,只需要把已选择的规格值和待选择的规格值组合起来,然后判断这个组合是否在allSpecKey中就可确定待选择的规格值是否可选。

那么 在渲染每一个规格值按钮组件时,只需要调用checkEnable方法,就可以检查是否可选,getSpec方法可以在选择完一个规格搭配后拿取过个搭配对象。如果没选择完的话,返回的是 null,刚刚方便识别是否有选择完成。当然,每次选中一个规格值时一定要执行setSelectedIds设置一下已经选中的规格Map。

相关文章

  • Flutter 多规格商品选择器核心工具 SKU

    团队打算用Flutter 覆写项目,但是遇到了一个有点恼火的事情,以前安卓和IOS在商品的多规格选择一般都有现成的...

  • 商城中开发商品sku及其他汇总

    1: sku商品,点击商品进去并不是商品的ID而是sku的id 基本表, 规格表 , 规格属性表 商品sku表 ...

  • 算法实际应用集(上)

    使用笛卡尔算法进行sku组合 需求 对商品规格进行排列组合,电商的sku商品组合 功能截图,对商品规格进行组合排列...

  • SKU商品规格选择

    在线demo地址 https://qdnzv.csb.app/[https://qdnzv.csb.app/] G...

  • SPU商品下的SKU单品选择

    1. SKU介绍 sku 是由多种不同的规格名的组成的 2. 分析 sku核心: 每一次选择sku的规格值就重新计...

  • SKU商品后台管理规格生成

    SKU商品后台管理规格生成 关于: 在做商品管理系统经常遇到一个需求,需要在前台动态添加商品SKU,然后生成表格,...

  • 商品中心

    商品定义 SPU: 规格, 商品描述, 品牌 SKU: 类目, 基础信息(税率, 属性, 生产信息), 其他参数 ...

  • 商品基本要素(摘自电商产品经理宝典)

    商品基本要素 类目、品牌、标题、商品属性、规格、价格、库存、SKU信息、商品图、商品详情描述、物流信息、商品信息标...

  • 商品多维sku设计

    数据库表设计 数据库关系 查询商品 查询商品所有的sku 查询某一个sku的所有规格 将t_product_att...

  • 淘宝专业名词解释

    SKU:宝贝的销售属性集合,供买家在下单时点选,如规格、颜色、尺寸等。商品编码商品款式:宝贝的款式种类,不区分规格...

网友评论

    本文标题:Flutter 多规格商品选择器核心工具 SKU

    本文链接:https://www.haomeiwen.com/subject/uqjvpqtx.html