| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 |
- /**
- * 轮胎优惠券匹配器
- * 用于判断商品是否匹配优惠券规则
- * 修改:每个商品只能匹配一张优惠券
- * @version 1.1.0
- */
- let TireCouponMatcher = (function() {
- // 私有辅助函数
- const helpers = {
- // 标准化品牌名称(忽略大小写和空格)
- normalizeBrand: function(brand) {
- return String(brand || '').trim().toLowerCase().replace(/\s+/g, '');
- },
- // 解析商品尺寸(提取数字)
- parseSize: function(size) {
- if (typeof size === 'number') return size;
- if (typeof size === 'string') {
- const match = size.match(/(\d+(\.\d+)?)/);
- return match ? parseFloat(match[1]) : NaN;
- }
- return NaN;
- },
- // 尺寸比较操作符
- sizeOperators: {
- '>=': (a, b) => a >= b,
- '<=': (a, b) => a <= b,
- '>': (a, b) => a > b,
- '<': (a, b) => a < b,
- '=': (a, b) => a === b,
- '==': (a, b) => a === b,
- '!=': (a, b) => a !== b
- }
- };
- /**
- * 匹配单个规则
- * @param {Object} item - 商品对象 {brandName, goodsSize}
- * @param {Object} rule - 规则对象 {couponType, ruleValue, ruleCondition}
- * @returns {boolean} 是否匹配
- */
- function matchSingleRule(item, rule) {
- const { couponType, ruleValue, ruleCondition } = rule;
- try {
- switch (couponType) {
- case 0: // 品牌匹配
- return helpers.normalizeBrand(item.brandName) ===
- helpers.normalizeBrand(ruleValue);
- case 1: // 尺寸匹配
- const itemSize = helpers.parseSize(item.goodsSize);
- const ruleSize = helpers.parseSize(ruleValue);
- if (isNaN(itemSize) || isNaN(ruleSize)) {
- return false;
- }
- // 获取比较操作符,默认为等值比较
- const operator = helpers.sizeOperators[ruleCondition] ||
- helpers.sizeOperators['='];
- return operator(itemSize, ruleSize);
- default:
- console.warn(`未知的规则类型: ${couponType}`);
- return false;
- }
- } catch (error) {
- console.error('规则匹配出错:', error);
- return false;
- }
- }
- /**
- * 匹配商品和优惠券规则列表
- * @param {Object} item - 商品对象 {brandName, goodsSize}
- * @param {Array} ruleList - 规则列表 [{couponType, ruleValue, ruleCondition}, ...]
- * @returns {boolean} 是否匹配所有规则
- */
- function matchRuleList(item, ruleList) {
- if (!ruleList || !Array.isArray(ruleList) || ruleList.length === 0) {
- return true; // 没有规则,默认匹配
- }
- // 检查所有规则是否都满足(AND 逻辑)
- return ruleList.every(rule => matchSingleRule(item, rule));
- }
- /**
- * 查找商品匹配的第一张优惠券ID
- * 修改:只返回第一张匹配的优惠券ID,而不是所有匹配的
- * @param {Object} item - 商品对象 {brandName, goodsSize}
- * @param {Array} couponList - 优惠券列表 [{couponId, tireCouponRuleList}, ...]
- * @returns {Array} 匹配的优惠券ID数组(最多一个元素)
- */
- function findMatchedCouponIds(item, couponList) {
- if (!couponList || !Array.isArray(couponList)) {
- return [];
- }
- // 查找第一张匹配的优惠券
- const matchedCoupon = couponList.find(coupon =>
- matchRuleList(item, coupon.tireCouponRuleList)
- );
- // 如果找到匹配的优惠券,返回其ID,否则返回空数组
- return matchedCoupon ? [matchedCoupon.couponId] : [];
- }
- /**
- * 批量匹配多个商品(每个商品只匹配一张优惠券)
- * 修改:每个商品只匹配第一张符合条件的优惠券
- * @param {Array} items - 商品对象数组
- * @param {Array} couponList - 优惠券列表
- * @returns {Object} 匹配结果 {matchedCouponIds, matchesByItem, totalMatches}
- */
- function batchMatch(items, couponList) {
- const matchedCouponIds = new Set();
- const matchesByItem = [];
- items.forEach((item, index) => {
- // 每个商品只匹配第一张优惠券
- const itemMatches = findMatchedCouponIds(item, couponList);
- // 将匹配到的优惠券ID添加到集合中
- if (itemMatches.length > 0) {
- matchedCouponIds.add(itemMatches[0]);
- }
- matchesByItem.push({
- itemIndex: index,
- brandName: item.brandName,
- goodsSize: item.goodsSize,
- matchedCouponIds: itemMatches
- });
- });
- return {
- matchedCouponIds: Array.from(matchedCouponIds),
- matchesByItem: matchesByItem,
- totalMatches: matchedCouponIds.size
- };
- }
- /**
- * 获取商品匹配的第一张优惠券ID(新增方法)
- * 用于明确表示只返回第一张匹配的优惠券
- * @param {Object} options - 配置对象
- * @param {Object} options.item - 商品对象 {brandName, goodsSize}
- * @param {Array} options.couponList - 优惠券列表
- * @returns {number|null} 匹配的优惠券ID,如果没有匹配则返回null
- */
- function findFirstMatchedCouponId(options) {
- if (!options || !options.item || !options.couponList) {
- console.error('缺少必要参数: item 和 couponList');
- return null;
- }
- const matchedIds = findMatchedCouponIds(options.item, options.couponList);
- return matchedIds.length > 0 ? matchedIds[0] : null;
- }
- // 公共 API
- return {
- /**
- * 判断商品是否匹配优惠券规则
- * @param {Object} options - 配置对象
- * @param {Object} options.item - 商品对象 {brandName, goodsSize}
- * @param {Array} options.ruleList - 优惠券规则列表
- * @returns {boolean} 是否匹配
- */
- isMatch: function(options) {
- if (!options || !options.item || !options.ruleList) {
- console.error('缺少必要参数: item 和 ruleList');
- return false;
- }
- return matchRuleList(options.item, options.ruleList);
- },
- /**
- * 获取商品匹配的所有优惠券ID
- * 注意:现在每个商品只会返回第一张匹配的优惠券ID
- * @param {Object} options - 配置对象
- * @param {Object} options.item - 商品对象 {brandName, goodsSize}
- * @param {Array} options.couponList - 优惠券列表
- * @returns {Array} 匹配的优惠券ID数组(最多一个元素)
- */
- getMatchedCouponIds: function(options) {
- if (!options || !options.item || !options.couponList) {
- console.error('缺少必要参数: item 和 couponList');
- return [];
- }
- return findMatchedCouponIds(options.item, options.couponList);
- },
- /**
- * 获取商品匹配的第一张优惠券ID(新增方法)
- * @param {Object} options - 配置对象
- * @param {Object} options.item - 商品对象 {brandName, goodsSize}
- * @param {Array} options.couponList - 优惠券列表
- * @returns {number|null} 匹配的优惠券ID,如果没有匹配则返回null
- */
- getFirstMatchedCouponId: function(options) {
- return findFirstMatchedCouponId(options);
- },
- /**
- * 批量匹配多个商品
- * 修改:每个商品只匹配第一张符合条件的优惠券
- * @param {Object} options - 配置对象
- * @param {Array} options.items - 商品对象数组
- * @param {Array} options.couponList - 优惠券列表
- * @returns {Object} 匹配结果
- */
- batchMatch: function(options) {
- console.info('options----', options);
- if (!options || !options.items || !options.couponList) {
- console.error('缺少必要参数: items 和 couponList');
- return { matchedCouponIds: [], matchesByItem: [], totalMatches: 0 };
- }
- return batchMatch(options.items, options.couponList);
- },
- /**
- * 验证数据格式
- * @param {Object} item - 商品对象
- * @returns {boolean} 数据格式是否正确
- */
- validateItem: function(item) {
- if (!item || typeof item !== 'object') {
- console.error('商品对象不能为空');
- return false;
- }
- const hasBrand = typeof item.brandName !== 'undefined';
- const hasSize = typeof item.goodsSize !== 'undefined';
- if (!hasBrand || !hasSize) {
- console.warn('商品对象缺少必要属性: brandName 或 goodsSize');
- }
- return hasBrand && hasSize;
- },
- /**
- * 版本信息
- */
- version: '1.1.0'
- };
- })();
- // 导出为模块(兼容 CommonJS 和 ES6 模块)
- if (typeof module !== 'undefined' && module.exports) {
- module.exports = TireCouponMatcher;
- }
- if (typeof window !== 'undefined') {
- window.TireCouponMatcher = TireCouponMatcher;
- }
|