multi-product-price-optimizer 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,203 @@
1
+ # 多商品组合最优价计算器
2
+
3
+ 一个用于计算多商品组合最优价格的JavaScript库。
4
+
5
+ ## 功能特点
6
+
7
+ - 支持多种商品组合优化计算
8
+ - 自动寻找最优价格组合
9
+ - 灵活的配置选项
10
+ - 支持多种模块格式(CommonJS、ESM、UMD)
11
+ - 无外部依赖,轻量级库
12
+
13
+ ## 安装
14
+
15
+ ```bash
16
+ npm install multi-product-price-optimizer
17
+ ```
18
+
19
+ ## 使用方法
20
+
21
+ ### 基本使用
22
+
23
+ ```javascript
24
+ import PriceOptimizer from 'multi-product-price-optimizer';
25
+
26
+ // 定义商品列表
27
+ const products = [
28
+ { id: '1', name: '小包装', price: 10, quantity: 5 },
29
+ { id: '2', name: '中包装', price: 18, quantity: 10 },
30
+ { id: '3', name: '大包装', price: 32, quantity: 20 }
31
+ ];
32
+
33
+ // 创建优化器实例
34
+ const optimizer = new PriceOptimizer(products);
35
+
36
+ // 计算最优组合
37
+ const result = optimizer.findOptimalCombination(25);
38
+ console.log(result);
39
+ /* 输出示例:
40
+ {
41
+ combination: [
42
+ { id: '3', name: '大包装', price: 32, quantity: 20, count: 1 },
43
+ { id: '1', name: '小包装', price: 10, quantity: 5, count: 1 }
44
+ ],
45
+ totalPrice: 42,
46
+ targetQuantity: 25,
47
+ unitPrice: 1.68
48
+ }
49
+ */
50
+ ```
51
+
52
+ ### 高级配置
53
+
54
+ ```javascript
55
+ // 使用自定义配置创建优化器
56
+ const optimizer = new PriceOptimizer(products, {
57
+ maxIterations: 20000, // 增加迭代次数提高精度
58
+ precision: 3 // 设置精度为3位小数
59
+ });
60
+
61
+ // 添加新商品
62
+ optimizer.addProduct({
63
+ id: '4',
64
+ name: '超大包装',
65
+ price: 60,
66
+ quantity: 50
67
+ });
68
+
69
+ // 更新现有商品
70
+ optimizer.updateProduct('1', { price: 9 });
71
+
72
+ // 删除商品
73
+ optimizer.removeProduct('2');
74
+ ```
75
+
76
+ ### 浏览器中使用
77
+
78
+ ```html
79
+ <!DOCTYPE html>
80
+ <html>
81
+ <head>
82
+ <meta charset="UTF-8">
83
+ <title>Price Optimizer Example</title>
84
+ </head>
85
+ <body>
86
+ <div id="result"></div>
87
+
88
+ <script src="node_modules/multi-product-price-optimizer/dist/index.umd.js"></script>
89
+ <script>
90
+ const products = [
91
+ { id: '1', name: '小包装', price: 10, quantity: 5 },
92
+ { id: '2', name: '中包装', price: 18, quantity: 10 },
93
+ { id: '3', name: '大包装', price: 32, quantity: 20 }
94
+ ];
95
+
96
+ const optimizer = new PriceOptimizer(products);
97
+ const result = optimizer.findOptimalCombination(25);
98
+
99
+ document.getElementById('result').innerHTML =
100
+ `<pre>${JSON.stringify(result, null, 2)}</pre>`;
101
+ </script>
102
+ </body>
103
+ </html>
104
+ ```
105
+
106
+ ## API 文档
107
+
108
+ ### PriceOptimizer 类
109
+
110
+ #### 构造函数
111
+ ```javascript
112
+ new PriceOptimizer(products, options)
113
+ ```
114
+
115
+ **参数:**
116
+ - `products` (Array): 商品数组,每个商品应包含 `id`, `name`, `price`, `quantity` 属性
117
+ - `options` (Object): 配置选项
118
+ - `maxIterations` (Number): 最大迭代次数,默认值为 10000
119
+ - `precision` (Number): 结果精度(小数位数),默认值为 2
120
+
121
+ #### 方法
122
+
123
+ ##### `findOptimalCombination(targetQuantity)`
124
+ 计算给定目标数量的最优商品组合
125
+
126
+ **参数:**
127
+ - `targetQuantity` (Number): 目标数量
128
+
129
+ **返回:**
130
+ - `Object`: 包含最优组合的结果对象
131
+
132
+ ##### `addProduct(product)`
133
+ 添加新商品
134
+
135
+ **参数:**
136
+ - `product` (Object): 商品对象,需包含 `id`, `name`, `price`, `quantity` 属性
137
+
138
+ ##### `removeProduct(productId)`
139
+ 根据 ID 删除商品
140
+
141
+ **参数:**
142
+ - `productId` (String): 商品 ID
143
+
144
+ ##### `updateProduct(productId, updates)`
145
+ 更新指定商品的信息
146
+
147
+ **参数:**
148
+ - `productId` (String): 商品 ID
149
+ - `updates` (Object): 需要更新的属性
150
+
151
+ ### 工具函数
152
+
153
+ #### `validateProducts(products)`
154
+ 验证商品数组是否符合要求
155
+
156
+ **参数:**
157
+ - `products` (Array): 待验证的商品数组
158
+
159
+ **返回:**
160
+ - `Boolean`: 验证结果
161
+
162
+ #### `formatCurrency(amount, currency)`
163
+ 格式化金额显示
164
+
165
+ **参数:**
166
+ - `amount` (Number): 金额
167
+ - `currency` (String): 货币符号,默认为 '¥'
168
+
169
+ **返回:**
170
+ - `String`: 格式化后的金额字符串
171
+
172
+ #### `calculateUnitPrice(product)`
173
+ 计算单个商品的单位价格
174
+
175
+ **参数:**
176
+ - `product` (Object): 商品对象
177
+
178
+ **返回:**
179
+ - `Number`: 单位价格
180
+
181
+ ## 开发指南
182
+
183
+ ```bash
184
+ # 安装依赖
185
+ npm install
186
+
187
+ # 运行测试
188
+ npm test
189
+
190
+ # 构建项目
191
+ npm run build
192
+
193
+ # 开发模式(监听文件变化并自动构建)
194
+ npm run dev
195
+ ```
196
+
197
+ ## 许可证
198
+
199
+ MIT
200
+
201
+ ## 贡献
202
+
203
+ 欢迎提交 Issue 或 Pull Request 来改进这个项目。
@@ -0,0 +1,176 @@
1
+ /**
2
+ * 多商品组合最优价格计算器
3
+ */
4
+ class PriceOptimizer {
5
+ /**
6
+ * 构造函数
7
+ * @param {Array} products - 商品列表
8
+ * @param {Object} options - 配置选项
9
+ */
10
+ constructor(products = [], options = {}) {
11
+ this.products = products;
12
+ this.options = {
13
+ maxIterations: options.maxIterations || 10000,
14
+ precision: options.precision || 2,
15
+ ...options
16
+ };
17
+ }
18
+
19
+ /**
20
+ * 计算最优组合
21
+ * @param {number} targetQuantity - 目标数量
22
+ * @returns {Object} 最优组合结果
23
+ */
24
+ findOptimalCombination(targetQuantity) {
25
+ if (targetQuantity <= 0) {
26
+ throw new Error('目标数量必须大于0');
27
+ }
28
+ if (!this.products || this.products.length === 0) {
29
+ throw new Error('商品列表不能为空');
30
+ }
31
+
32
+ // 按单价从低到高排序
33
+ const sortedProducts = [...this.products].sort((a, b) => a.price / a.quantity - b.price / b.quantity);
34
+ let bestCombination = null;
35
+ let bestPrice = Infinity;
36
+
37
+ // 遍历所有可能的组合
38
+ for (let i = 0; i < this.options.maxIterations; i++) {
39
+ const combination = this._generateCombination(sortedProducts, targetQuantity);
40
+ if (combination) {
41
+ const totalPrice = this._calculateTotalPrice(combination);
42
+ if (totalPrice < bestPrice) {
43
+ bestPrice = totalPrice;
44
+ bestCombination = combination;
45
+ }
46
+ }
47
+ }
48
+ return {
49
+ combination: bestCombination,
50
+ totalPrice: parseFloat(bestPrice.toFixed(this.options.precision)),
51
+ targetQuantity,
52
+ unitPrice: bestCombination ? parseFloat((bestPrice / targetQuantity).toFixed(this.options.precision)) : 0
53
+ };
54
+ }
55
+
56
+ /**
57
+ * 生成一个可能的组合
58
+ * @private
59
+ */
60
+ _generateCombination(products, targetQuantity) {
61
+ const combination = [];
62
+ let remainingQuantity = targetQuantity;
63
+ for (const product of products) {
64
+ if (remainingQuantity <= 0) break;
65
+
66
+ // 计算最多需要多少个该商品
67
+ const maxCount = Math.ceil(remainingQuantity / product.quantity);
68
+ // 随机选择0到maxCount之间的数量
69
+ const count = Math.floor(Math.random() * (maxCount + 1));
70
+ if (count > 0) {
71
+ combination.push({
72
+ ...product,
73
+ count
74
+ });
75
+ remainingQuantity -= count * product.quantity;
76
+ }
77
+ }
78
+
79
+ // 如果还有剩余数量,用最便宜的商品补足
80
+ if (remainingQuantity > 0 && products.length > 0) {
81
+ const cheapestProduct = products[0];
82
+ const additionalCount = Math.ceil(remainingQuantity / cheapestProduct.quantity);
83
+ const existingItem = combination.find(item => item.id === cheapestProduct.id);
84
+ if (existingItem) {
85
+ existingItem.count += additionalCount;
86
+ } else {
87
+ combination.push({
88
+ ...cheapestProduct,
89
+ count: additionalCount
90
+ });
91
+ }
92
+ }
93
+ return combination;
94
+ }
95
+
96
+ /**
97
+ * 计算组合总价
98
+ * @private
99
+ */
100
+ _calculateTotalPrice(combination) {
101
+ return combination.reduce((total, item) => {
102
+ return total + item.price * item.count;
103
+ }, 0);
104
+ }
105
+
106
+ /**
107
+ * 添加商品
108
+ * @param {Object} product - 商品信息
109
+ */
110
+ addProduct(product) {
111
+ if (!product.id || !product.name || !product.price || !product.quantity) {
112
+ throw new Error('商品信息不完整');
113
+ }
114
+ this.products.push(product);
115
+ }
116
+
117
+ /**
118
+ * 移除商品
119
+ * @param {string} productId - 商品ID
120
+ */
121
+ removeProduct(productId) {
122
+ this.products = this.products.filter(p => p.id !== productId);
123
+ }
124
+
125
+ /**
126
+ * 更新商品
127
+ * @param {string} productId - 商品ID
128
+ * @param {Object} updates - 更新信息
129
+ */
130
+ updateProduct(productId, updates) {
131
+ const index = this.products.findIndex(p => p.id === productId);
132
+ if (index !== -1) {
133
+ this.products[index] = {
134
+ ...this.products[index],
135
+ ...updates
136
+ };
137
+ }
138
+ }
139
+ }
140
+
141
+ /**
142
+ * 格式化货币
143
+ * @param {number} amount - 金额
144
+ * @param {string} currency - 货币符号
145
+ * @returns {string} 格式化后的货币字符串
146
+ */
147
+ function formatCurrency(amount, currency = '¥') {
148
+ return `${currency}${amount.toFixed(2)}`;
149
+ }
150
+
151
+ /**
152
+ * 验证商品数据
153
+ * @param {Array} products - 商品列表
154
+ * @returns {boolean} 是否有效
155
+ */
156
+ function validateProducts(products) {
157
+ if (!Array.isArray(products) || products.length === 0) {
158
+ return false;
159
+ }
160
+ return products.every(product => product.id && product.name && typeof product.price === 'number' && product.price > 0 && typeof product.quantity === 'number' && product.quantity > 0);
161
+ }
162
+
163
+ /**
164
+ * 计算单个商品的单价
165
+ * @param {Object} product - 商品信息
166
+ * @returns {number} 单价
167
+ */
168
+ function calculateUnitPrice(product) {
169
+ if (!product || !product.price || !product.quantity) {
170
+ return 0;
171
+ }
172
+ return product.price / product.quantity;
173
+ }
174
+
175
+ export { PriceOptimizer, calculateUnitPrice, formatCurrency, validateProducts };
176
+ //# sourceMappingURL=index.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.esm.js","sources":["../src/PriceOptimizer.js","../src/utils.js"],"sourcesContent":["\r\n/**\r\n * 多商品组合最优价格计算器\r\n */\r\nclass PriceOptimizer {\r\n /**\r\n * 构造函数\r\n * @param {Array} products - 商品列表\r\n * @param {Object} options - 配置选项\r\n */\r\n constructor(products = [], options = {}) {\r\n this.products = products;\r\n this.options = {\r\n maxIterations: options.maxIterations || 10000,\r\n precision: options.precision || 2,\r\n ...options\r\n };\r\n }\r\n\r\n /**\r\n * 计算最优组合\r\n * @param {number} targetQuantity - 目标数量\r\n * @returns {Object} 最优组合结果\r\n */\r\n findOptimalCombination(targetQuantity) {\r\n if (targetQuantity <= 0) {\r\n throw new Error('目标数量必须大于0');\r\n }\r\n\r\n if (!this.products || this.products.length === 0) {\r\n throw new Error('商品列表不能为空');\r\n }\r\n\r\n // 按单价从低到高排序\r\n const sortedProducts = [...this.products].sort((a, b) => \r\n (a.price / a.quantity) - (b.price / b.quantity)\r\n );\r\n\r\n let bestCombination = null;\r\n let bestPrice = Infinity;\r\n\r\n // 遍历所有可能的组合\r\n for (let i = 0; i < this.options.maxIterations; i++) {\r\n const combination = this._generateCombination(sortedProducts, targetQuantity);\r\n if (combination) {\r\n const totalPrice = this._calculateTotalPrice(combination);\r\n if (totalPrice < bestPrice) {\r\n bestPrice = totalPrice;\r\n bestCombination = combination;\r\n }\r\n }\r\n }\r\n\r\n return {\r\n combination: bestCombination,\r\n totalPrice: parseFloat(bestPrice.toFixed(this.options.precision)),\r\n targetQuantity,\r\n unitPrice: bestCombination ? \r\n parseFloat((bestPrice / targetQuantity).toFixed(this.options.precision)) : 0\r\n };\r\n }\r\n\r\n /**\r\n * 生成一个可能的组合\r\n * @private\r\n */\r\n _generateCombination(products, targetQuantity) {\r\n const combination = [];\r\n let remainingQuantity = targetQuantity;\r\n\r\n for (const product of products) {\r\n if (remainingQuantity <= 0) break;\r\n \r\n // 计算最多需要多少个该商品\r\n const maxCount = Math.ceil(remainingQuantity / product.quantity);\r\n // 随机选择0到maxCount之间的数量\r\n const count = Math.floor(Math.random() * (maxCount + 1));\r\n \r\n if (count > 0) {\r\n combination.push({ ...product, count });\r\n remainingQuantity -= count * product.quantity;\r\n }\r\n }\r\n\r\n // 如果还有剩余数量,用最便宜的商品补足\r\n if (remainingQuantity > 0 && products.length > 0) {\r\n const cheapestProduct = products[0];\r\n const additionalCount = Math.ceil(remainingQuantity / cheapestProduct.quantity);\r\n const existingItem = combination.find(item => item.id === cheapestProduct.id);\r\n \r\n if (existingItem) {\r\n existingItem.count += additionalCount;\r\n } else {\r\n combination.push({ ...cheapestProduct, count: additionalCount });\r\n }\r\n }\r\n\r\n return combination;\r\n }\r\n\r\n /**\r\n * 计算组合总价\r\n * @private\r\n */\r\n _calculateTotalPrice(combination) {\r\n return combination.reduce((total, item) => {\r\n return total + (item.price * item.count);\r\n }, 0);\r\n }\r\n\r\n /**\r\n * 添加商品\r\n * @param {Object} product - 商品信息\r\n */\r\n addProduct(product) {\r\n if (!product.id || !product.name || !product.price || !product.quantity) {\r\n throw new Error('商品信息不完整');\r\n }\r\n this.products.push(product);\r\n }\r\n\r\n /**\r\n * 移除商品\r\n * @param {string} productId - 商品ID\r\n */\r\n removeProduct(productId) {\r\n this.products = this.products.filter(p => p.id !== productId);\r\n }\r\n\r\n /**\r\n * 更新商品\r\n * @param {string} productId - 商品ID\r\n * @param {Object} updates - 更新信息\r\n */\r\n updateProduct(productId, updates) {\r\n const index = this.products.findIndex(p => p.id === productId);\r\n if (index !== -1) {\r\n this.products[index] = { ...this.products[index], ...updates };\r\n }\r\n }\r\n}\r\n\r\nexport default PriceOptimizer;\r\n","\r\n/**\r\n * 格式化货币\r\n * @param {number} amount - 金额\r\n * @param {string} currency - 货币符号\r\n * @returns {string} 格式化后的货币字符串\r\n */\r\nexport function formatCurrency(amount, currency = '¥') {\r\n return `${currency}${amount.toFixed(2)}`;\r\n}\r\n\r\n/**\r\n * 验证商品数据\r\n * @param {Array} products - 商品列表\r\n * @returns {boolean} 是否有效\r\n */\r\nexport function validateProducts(products) {\r\n if (!Array.isArray(products) || products.length === 0) {\r\n return false;\r\n }\r\n\r\n return products.every(product => \r\n product.id && \r\n product.name && \r\n typeof product.price === 'number' && \r\n product.price > 0 &&\r\n typeof product.quantity === 'number' && \r\n product.quantity > 0\r\n );\r\n}\r\n\r\n/**\r\n * 计算单个商品的单价\r\n * @param {Object} product - 商品信息\r\n * @returns {number} 单价\r\n */\r\nexport function calculateUnitPrice(product) {\r\n if (!product || !product.price || !product.quantity) {\r\n return 0;\r\n }\r\n return product.price / product.quantity;\r\n}\r\n"],"names":["PriceOptimizer","constructor","products","options","maxIterations","precision","findOptimalCombination","targetQuantity","Error","length","sortedProducts","sort","a","b","price","quantity","bestCombination","bestPrice","Infinity","i","combination","_generateCombination","totalPrice","_calculateTotalPrice","parseFloat","toFixed","unitPrice","remainingQuantity","product","maxCount","Math","ceil","count","floor","random","push","cheapestProduct","additionalCount","existingItem","find","item","id","reduce","total","addProduct","name","removeProduct","productId","filter","p","updateProduct","updates","index","findIndex","formatCurrency","amount","currency","validateProducts","Array","isArray","every","calculateUnitPrice"],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,181 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * 多商品组合最优价格计算器
5
+ */
6
+ class PriceOptimizer {
7
+ /**
8
+ * 构造函数
9
+ * @param {Array} products - 商品列表
10
+ * @param {Object} options - 配置选项
11
+ */
12
+ constructor(products = [], options = {}) {
13
+ this.products = products;
14
+ this.options = {
15
+ maxIterations: options.maxIterations || 10000,
16
+ precision: options.precision || 2,
17
+ ...options
18
+ };
19
+ }
20
+
21
+ /**
22
+ * 计算最优组合
23
+ * @param {number} targetQuantity - 目标数量
24
+ * @returns {Object} 最优组合结果
25
+ */
26
+ findOptimalCombination(targetQuantity) {
27
+ if (targetQuantity <= 0) {
28
+ throw new Error('目标数量必须大于0');
29
+ }
30
+ if (!this.products || this.products.length === 0) {
31
+ throw new Error('商品列表不能为空');
32
+ }
33
+
34
+ // 按单价从低到高排序
35
+ const sortedProducts = [...this.products].sort((a, b) => a.price / a.quantity - b.price / b.quantity);
36
+ let bestCombination = null;
37
+ let bestPrice = Infinity;
38
+
39
+ // 遍历所有可能的组合
40
+ for (let i = 0; i < this.options.maxIterations; i++) {
41
+ const combination = this._generateCombination(sortedProducts, targetQuantity);
42
+ if (combination) {
43
+ const totalPrice = this._calculateTotalPrice(combination);
44
+ if (totalPrice < bestPrice) {
45
+ bestPrice = totalPrice;
46
+ bestCombination = combination;
47
+ }
48
+ }
49
+ }
50
+ return {
51
+ combination: bestCombination,
52
+ totalPrice: parseFloat(bestPrice.toFixed(this.options.precision)),
53
+ targetQuantity,
54
+ unitPrice: bestCombination ? parseFloat((bestPrice / targetQuantity).toFixed(this.options.precision)) : 0
55
+ };
56
+ }
57
+
58
+ /**
59
+ * 生成一个可能的组合
60
+ * @private
61
+ */
62
+ _generateCombination(products, targetQuantity) {
63
+ const combination = [];
64
+ let remainingQuantity = targetQuantity;
65
+ for (const product of products) {
66
+ if (remainingQuantity <= 0) break;
67
+
68
+ // 计算最多需要多少个该商品
69
+ const maxCount = Math.ceil(remainingQuantity / product.quantity);
70
+ // 随机选择0到maxCount之间的数量
71
+ const count = Math.floor(Math.random() * (maxCount + 1));
72
+ if (count > 0) {
73
+ combination.push({
74
+ ...product,
75
+ count
76
+ });
77
+ remainingQuantity -= count * product.quantity;
78
+ }
79
+ }
80
+
81
+ // 如果还有剩余数量,用最便宜的商品补足
82
+ if (remainingQuantity > 0 && products.length > 0) {
83
+ const cheapestProduct = products[0];
84
+ const additionalCount = Math.ceil(remainingQuantity / cheapestProduct.quantity);
85
+ const existingItem = combination.find(item => item.id === cheapestProduct.id);
86
+ if (existingItem) {
87
+ existingItem.count += additionalCount;
88
+ } else {
89
+ combination.push({
90
+ ...cheapestProduct,
91
+ count: additionalCount
92
+ });
93
+ }
94
+ }
95
+ return combination;
96
+ }
97
+
98
+ /**
99
+ * 计算组合总价
100
+ * @private
101
+ */
102
+ _calculateTotalPrice(combination) {
103
+ return combination.reduce((total, item) => {
104
+ return total + item.price * item.count;
105
+ }, 0);
106
+ }
107
+
108
+ /**
109
+ * 添加商品
110
+ * @param {Object} product - 商品信息
111
+ */
112
+ addProduct(product) {
113
+ if (!product.id || !product.name || !product.price || !product.quantity) {
114
+ throw new Error('商品信息不完整');
115
+ }
116
+ this.products.push(product);
117
+ }
118
+
119
+ /**
120
+ * 移除商品
121
+ * @param {string} productId - 商品ID
122
+ */
123
+ removeProduct(productId) {
124
+ this.products = this.products.filter(p => p.id !== productId);
125
+ }
126
+
127
+ /**
128
+ * 更新商品
129
+ * @param {string} productId - 商品ID
130
+ * @param {Object} updates - 更新信息
131
+ */
132
+ updateProduct(productId, updates) {
133
+ const index = this.products.findIndex(p => p.id === productId);
134
+ if (index !== -1) {
135
+ this.products[index] = {
136
+ ...this.products[index],
137
+ ...updates
138
+ };
139
+ }
140
+ }
141
+ }
142
+
143
+ /**
144
+ * 格式化货币
145
+ * @param {number} amount - 金额
146
+ * @param {string} currency - 货币符号
147
+ * @returns {string} 格式化后的货币字符串
148
+ */
149
+ function formatCurrency(amount, currency = '¥') {
150
+ return `${currency}${amount.toFixed(2)}`;
151
+ }
152
+
153
+ /**
154
+ * 验证商品数据
155
+ * @param {Array} products - 商品列表
156
+ * @returns {boolean} 是否有效
157
+ */
158
+ function validateProducts(products) {
159
+ if (!Array.isArray(products) || products.length === 0) {
160
+ return false;
161
+ }
162
+ return products.every(product => product.id && product.name && typeof product.price === 'number' && product.price > 0 && typeof product.quantity === 'number' && product.quantity > 0);
163
+ }
164
+
165
+ /**
166
+ * 计算单个商品的单价
167
+ * @param {Object} product - 商品信息
168
+ * @returns {number} 单价
169
+ */
170
+ function calculateUnitPrice(product) {
171
+ if (!product || !product.price || !product.quantity) {
172
+ return 0;
173
+ }
174
+ return product.price / product.quantity;
175
+ }
176
+
177
+ exports.PriceOptimizer = PriceOptimizer;
178
+ exports.calculateUnitPrice = calculateUnitPrice;
179
+ exports.formatCurrency = formatCurrency;
180
+ exports.validateProducts = validateProducts;
181
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../src/PriceOptimizer.js","../src/utils.js"],"sourcesContent":["\r\n/**\r\n * 多商品组合最优价格计算器\r\n */\r\nclass PriceOptimizer {\r\n /**\r\n * 构造函数\r\n * @param {Array} products - 商品列表\r\n * @param {Object} options - 配置选项\r\n */\r\n constructor(products = [], options = {}) {\r\n this.products = products;\r\n this.options = {\r\n maxIterations: options.maxIterations || 10000,\r\n precision: options.precision || 2,\r\n ...options\r\n };\r\n }\r\n\r\n /**\r\n * 计算最优组合\r\n * @param {number} targetQuantity - 目标数量\r\n * @returns {Object} 最优组合结果\r\n */\r\n findOptimalCombination(targetQuantity) {\r\n if (targetQuantity <= 0) {\r\n throw new Error('目标数量必须大于0');\r\n }\r\n\r\n if (!this.products || this.products.length === 0) {\r\n throw new Error('商品列表不能为空');\r\n }\r\n\r\n // 按单价从低到高排序\r\n const sortedProducts = [...this.products].sort((a, b) => \r\n (a.price / a.quantity) - (b.price / b.quantity)\r\n );\r\n\r\n let bestCombination = null;\r\n let bestPrice = Infinity;\r\n\r\n // 遍历所有可能的组合\r\n for (let i = 0; i < this.options.maxIterations; i++) {\r\n const combination = this._generateCombination(sortedProducts, targetQuantity);\r\n if (combination) {\r\n const totalPrice = this._calculateTotalPrice(combination);\r\n if (totalPrice < bestPrice) {\r\n bestPrice = totalPrice;\r\n bestCombination = combination;\r\n }\r\n }\r\n }\r\n\r\n return {\r\n combination: bestCombination,\r\n totalPrice: parseFloat(bestPrice.toFixed(this.options.precision)),\r\n targetQuantity,\r\n unitPrice: bestCombination ? \r\n parseFloat((bestPrice / targetQuantity).toFixed(this.options.precision)) : 0\r\n };\r\n }\r\n\r\n /**\r\n * 生成一个可能的组合\r\n * @private\r\n */\r\n _generateCombination(products, targetQuantity) {\r\n const combination = [];\r\n let remainingQuantity = targetQuantity;\r\n\r\n for (const product of products) {\r\n if (remainingQuantity <= 0) break;\r\n \r\n // 计算最多需要多少个该商品\r\n const maxCount = Math.ceil(remainingQuantity / product.quantity);\r\n // 随机选择0到maxCount之间的数量\r\n const count = Math.floor(Math.random() * (maxCount + 1));\r\n \r\n if (count > 0) {\r\n combination.push({ ...product, count });\r\n remainingQuantity -= count * product.quantity;\r\n }\r\n }\r\n\r\n // 如果还有剩余数量,用最便宜的商品补足\r\n if (remainingQuantity > 0 && products.length > 0) {\r\n const cheapestProduct = products[0];\r\n const additionalCount = Math.ceil(remainingQuantity / cheapestProduct.quantity);\r\n const existingItem = combination.find(item => item.id === cheapestProduct.id);\r\n \r\n if (existingItem) {\r\n existingItem.count += additionalCount;\r\n } else {\r\n combination.push({ ...cheapestProduct, count: additionalCount });\r\n }\r\n }\r\n\r\n return combination;\r\n }\r\n\r\n /**\r\n * 计算组合总价\r\n * @private\r\n */\r\n _calculateTotalPrice(combination) {\r\n return combination.reduce((total, item) => {\r\n return total + (item.price * item.count);\r\n }, 0);\r\n }\r\n\r\n /**\r\n * 添加商品\r\n * @param {Object} product - 商品信息\r\n */\r\n addProduct(product) {\r\n if (!product.id || !product.name || !product.price || !product.quantity) {\r\n throw new Error('商品信息不完整');\r\n }\r\n this.products.push(product);\r\n }\r\n\r\n /**\r\n * 移除商品\r\n * @param {string} productId - 商品ID\r\n */\r\n removeProduct(productId) {\r\n this.products = this.products.filter(p => p.id !== productId);\r\n }\r\n\r\n /**\r\n * 更新商品\r\n * @param {string} productId - 商品ID\r\n * @param {Object} updates - 更新信息\r\n */\r\n updateProduct(productId, updates) {\r\n const index = this.products.findIndex(p => p.id === productId);\r\n if (index !== -1) {\r\n this.products[index] = { ...this.products[index], ...updates };\r\n }\r\n }\r\n}\r\n\r\nexport default PriceOptimizer;\r\n","\r\n/**\r\n * 格式化货币\r\n * @param {number} amount - 金额\r\n * @param {string} currency - 货币符号\r\n * @returns {string} 格式化后的货币字符串\r\n */\r\nexport function formatCurrency(amount, currency = '¥') {\r\n return `${currency}${amount.toFixed(2)}`;\r\n}\r\n\r\n/**\r\n * 验证商品数据\r\n * @param {Array} products - 商品列表\r\n * @returns {boolean} 是否有效\r\n */\r\nexport function validateProducts(products) {\r\n if (!Array.isArray(products) || products.length === 0) {\r\n return false;\r\n }\r\n\r\n return products.every(product => \r\n product.id && \r\n product.name && \r\n typeof product.price === 'number' && \r\n product.price > 0 &&\r\n typeof product.quantity === 'number' && \r\n product.quantity > 0\r\n );\r\n}\r\n\r\n/**\r\n * 计算单个商品的单价\r\n * @param {Object} product - 商品信息\r\n * @returns {number} 单价\r\n */\r\nexport function calculateUnitPrice(product) {\r\n if (!product || !product.price || !product.quantity) {\r\n return 0;\r\n }\r\n return product.price / product.quantity;\r\n}\r\n"],"names":["PriceOptimizer","constructor","products","options","maxIterations","precision","findOptimalCombination","targetQuantity","Error","length","sortedProducts","sort","a","b","price","quantity","bestCombination","bestPrice","Infinity","i","combination","_generateCombination","totalPrice","_calculateTotalPrice","parseFloat","toFixed","unitPrice","remainingQuantity","product","maxCount","Math","ceil","count","floor","random","push","cheapestProduct","additionalCount","existingItem","find","item","id","reduce","total","addProduct","name","removeProduct","productId","filter","p","updateProduct","updates","index","findIndex","formatCurrency","amount","currency","validateProducts","Array","isArray","every","calculateUnitPrice"],"mappings":"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"}
@@ -0,0 +1,187 @@
1
+ (function (global, factory) {
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3
+ typeof define === 'function' && define.amd ? define(['exports'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.PriceOptimizer = {}));
5
+ })(this, (function (exports) { 'use strict';
6
+
7
+ /**
8
+ * 多商品组合最优价格计算器
9
+ */
10
+ class PriceOptimizer {
11
+ /**
12
+ * 构造函数
13
+ * @param {Array} products - 商品列表
14
+ * @param {Object} options - 配置选项
15
+ */
16
+ constructor(products = [], options = {}) {
17
+ this.products = products;
18
+ this.options = {
19
+ maxIterations: options.maxIterations || 10000,
20
+ precision: options.precision || 2,
21
+ ...options
22
+ };
23
+ }
24
+
25
+ /**
26
+ * 计算最优组合
27
+ * @param {number} targetQuantity - 目标数量
28
+ * @returns {Object} 最优组合结果
29
+ */
30
+ findOptimalCombination(targetQuantity) {
31
+ if (targetQuantity <= 0) {
32
+ throw new Error('目标数量必须大于0');
33
+ }
34
+ if (!this.products || this.products.length === 0) {
35
+ throw new Error('商品列表不能为空');
36
+ }
37
+
38
+ // 按单价从低到高排序
39
+ const sortedProducts = [...this.products].sort((a, b) => a.price / a.quantity - b.price / b.quantity);
40
+ let bestCombination = null;
41
+ let bestPrice = Infinity;
42
+
43
+ // 遍历所有可能的组合
44
+ for (let i = 0; i < this.options.maxIterations; i++) {
45
+ const combination = this._generateCombination(sortedProducts, targetQuantity);
46
+ if (combination) {
47
+ const totalPrice = this._calculateTotalPrice(combination);
48
+ if (totalPrice < bestPrice) {
49
+ bestPrice = totalPrice;
50
+ bestCombination = combination;
51
+ }
52
+ }
53
+ }
54
+ return {
55
+ combination: bestCombination,
56
+ totalPrice: parseFloat(bestPrice.toFixed(this.options.precision)),
57
+ targetQuantity,
58
+ unitPrice: bestCombination ? parseFloat((bestPrice / targetQuantity).toFixed(this.options.precision)) : 0
59
+ };
60
+ }
61
+
62
+ /**
63
+ * 生成一个可能的组合
64
+ * @private
65
+ */
66
+ _generateCombination(products, targetQuantity) {
67
+ const combination = [];
68
+ let remainingQuantity = targetQuantity;
69
+ for (const product of products) {
70
+ if (remainingQuantity <= 0) break;
71
+
72
+ // 计算最多需要多少个该商品
73
+ const maxCount = Math.ceil(remainingQuantity / product.quantity);
74
+ // 随机选择0到maxCount之间的数量
75
+ const count = Math.floor(Math.random() * (maxCount + 1));
76
+ if (count > 0) {
77
+ combination.push({
78
+ ...product,
79
+ count
80
+ });
81
+ remainingQuantity -= count * product.quantity;
82
+ }
83
+ }
84
+
85
+ // 如果还有剩余数量,用最便宜的商品补足
86
+ if (remainingQuantity > 0 && products.length > 0) {
87
+ const cheapestProduct = products[0];
88
+ const additionalCount = Math.ceil(remainingQuantity / cheapestProduct.quantity);
89
+ const existingItem = combination.find(item => item.id === cheapestProduct.id);
90
+ if (existingItem) {
91
+ existingItem.count += additionalCount;
92
+ } else {
93
+ combination.push({
94
+ ...cheapestProduct,
95
+ count: additionalCount
96
+ });
97
+ }
98
+ }
99
+ return combination;
100
+ }
101
+
102
+ /**
103
+ * 计算组合总价
104
+ * @private
105
+ */
106
+ _calculateTotalPrice(combination) {
107
+ return combination.reduce((total, item) => {
108
+ return total + item.price * item.count;
109
+ }, 0);
110
+ }
111
+
112
+ /**
113
+ * 添加商品
114
+ * @param {Object} product - 商品信息
115
+ */
116
+ addProduct(product) {
117
+ if (!product.id || !product.name || !product.price || !product.quantity) {
118
+ throw new Error('商品信息不完整');
119
+ }
120
+ this.products.push(product);
121
+ }
122
+
123
+ /**
124
+ * 移除商品
125
+ * @param {string} productId - 商品ID
126
+ */
127
+ removeProduct(productId) {
128
+ this.products = this.products.filter(p => p.id !== productId);
129
+ }
130
+
131
+ /**
132
+ * 更新商品
133
+ * @param {string} productId - 商品ID
134
+ * @param {Object} updates - 更新信息
135
+ */
136
+ updateProduct(productId, updates) {
137
+ const index = this.products.findIndex(p => p.id === productId);
138
+ if (index !== -1) {
139
+ this.products[index] = {
140
+ ...this.products[index],
141
+ ...updates
142
+ };
143
+ }
144
+ }
145
+ }
146
+
147
+ /**
148
+ * 格式化货币
149
+ * @param {number} amount - 金额
150
+ * @param {string} currency - 货币符号
151
+ * @returns {string} 格式化后的货币字符串
152
+ */
153
+ function formatCurrency(amount, currency = '¥') {
154
+ return `${currency}${amount.toFixed(2)}`;
155
+ }
156
+
157
+ /**
158
+ * 验证商品数据
159
+ * @param {Array} products - 商品列表
160
+ * @returns {boolean} 是否有效
161
+ */
162
+ function validateProducts(products) {
163
+ if (!Array.isArray(products) || products.length === 0) {
164
+ return false;
165
+ }
166
+ return products.every(product => product.id && product.name && typeof product.price === 'number' && product.price > 0 && typeof product.quantity === 'number' && product.quantity > 0);
167
+ }
168
+
169
+ /**
170
+ * 计算单个商品的单价
171
+ * @param {Object} product - 商品信息
172
+ * @returns {number} 单价
173
+ */
174
+ function calculateUnitPrice(product) {
175
+ if (!product || !product.price || !product.quantity) {
176
+ return 0;
177
+ }
178
+ return product.price / product.quantity;
179
+ }
180
+
181
+ exports.PriceOptimizer = PriceOptimizer;
182
+ exports.calculateUnitPrice = calculateUnitPrice;
183
+ exports.formatCurrency = formatCurrency;
184
+ exports.validateProducts = validateProducts;
185
+
186
+ }));
187
+ //# sourceMappingURL=index.umd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.umd.js","sources":["../src/PriceOptimizer.js","../src/utils.js"],"sourcesContent":["\r\n/**\r\n * 多商品组合最优价格计算器\r\n */\r\nclass PriceOptimizer {\r\n /**\r\n * 构造函数\r\n * @param {Array} products - 商品列表\r\n * @param {Object} options - 配置选项\r\n */\r\n constructor(products = [], options = {}) {\r\n this.products = products;\r\n this.options = {\r\n maxIterations: options.maxIterations || 10000,\r\n precision: options.precision || 2,\r\n ...options\r\n };\r\n }\r\n\r\n /**\r\n * 计算最优组合\r\n * @param {number} targetQuantity - 目标数量\r\n * @returns {Object} 最优组合结果\r\n */\r\n findOptimalCombination(targetQuantity) {\r\n if (targetQuantity <= 0) {\r\n throw new Error('目标数量必须大于0');\r\n }\r\n\r\n if (!this.products || this.products.length === 0) {\r\n throw new Error('商品列表不能为空');\r\n }\r\n\r\n // 按单价从低到高排序\r\n const sortedProducts = [...this.products].sort((a, b) => \r\n (a.price / a.quantity) - (b.price / b.quantity)\r\n );\r\n\r\n let bestCombination = null;\r\n let bestPrice = Infinity;\r\n\r\n // 遍历所有可能的组合\r\n for (let i = 0; i < this.options.maxIterations; i++) {\r\n const combination = this._generateCombination(sortedProducts, targetQuantity);\r\n if (combination) {\r\n const totalPrice = this._calculateTotalPrice(combination);\r\n if (totalPrice < bestPrice) {\r\n bestPrice = totalPrice;\r\n bestCombination = combination;\r\n }\r\n }\r\n }\r\n\r\n return {\r\n combination: bestCombination,\r\n totalPrice: parseFloat(bestPrice.toFixed(this.options.precision)),\r\n targetQuantity,\r\n unitPrice: bestCombination ? \r\n parseFloat((bestPrice / targetQuantity).toFixed(this.options.precision)) : 0\r\n };\r\n }\r\n\r\n /**\r\n * 生成一个可能的组合\r\n * @private\r\n */\r\n _generateCombination(products, targetQuantity) {\r\n const combination = [];\r\n let remainingQuantity = targetQuantity;\r\n\r\n for (const product of products) {\r\n if (remainingQuantity <= 0) break;\r\n \r\n // 计算最多需要多少个该商品\r\n const maxCount = Math.ceil(remainingQuantity / product.quantity);\r\n // 随机选择0到maxCount之间的数量\r\n const count = Math.floor(Math.random() * (maxCount + 1));\r\n \r\n if (count > 0) {\r\n combination.push({ ...product, count });\r\n remainingQuantity -= count * product.quantity;\r\n }\r\n }\r\n\r\n // 如果还有剩余数量,用最便宜的商品补足\r\n if (remainingQuantity > 0 && products.length > 0) {\r\n const cheapestProduct = products[0];\r\n const additionalCount = Math.ceil(remainingQuantity / cheapestProduct.quantity);\r\n const existingItem = combination.find(item => item.id === cheapestProduct.id);\r\n \r\n if (existingItem) {\r\n existingItem.count += additionalCount;\r\n } else {\r\n combination.push({ ...cheapestProduct, count: additionalCount });\r\n }\r\n }\r\n\r\n return combination;\r\n }\r\n\r\n /**\r\n * 计算组合总价\r\n * @private\r\n */\r\n _calculateTotalPrice(combination) {\r\n return combination.reduce((total, item) => {\r\n return total + (item.price * item.count);\r\n }, 0);\r\n }\r\n\r\n /**\r\n * 添加商品\r\n * @param {Object} product - 商品信息\r\n */\r\n addProduct(product) {\r\n if (!product.id || !product.name || !product.price || !product.quantity) {\r\n throw new Error('商品信息不完整');\r\n }\r\n this.products.push(product);\r\n }\r\n\r\n /**\r\n * 移除商品\r\n * @param {string} productId - 商品ID\r\n */\r\n removeProduct(productId) {\r\n this.products = this.products.filter(p => p.id !== productId);\r\n }\r\n\r\n /**\r\n * 更新商品\r\n * @param {string} productId - 商品ID\r\n * @param {Object} updates - 更新信息\r\n */\r\n updateProduct(productId, updates) {\r\n const index = this.products.findIndex(p => p.id === productId);\r\n if (index !== -1) {\r\n this.products[index] = { ...this.products[index], ...updates };\r\n }\r\n }\r\n}\r\n\r\nexport default PriceOptimizer;\r\n","\r\n/**\r\n * 格式化货币\r\n * @param {number} amount - 金额\r\n * @param {string} currency - 货币符号\r\n * @returns {string} 格式化后的货币字符串\r\n */\r\nexport function formatCurrency(amount, currency = '¥') {\r\n return `${currency}${amount.toFixed(2)}`;\r\n}\r\n\r\n/**\r\n * 验证商品数据\r\n * @param {Array} products - 商品列表\r\n * @returns {boolean} 是否有效\r\n */\r\nexport function validateProducts(products) {\r\n if (!Array.isArray(products) || products.length === 0) {\r\n return false;\r\n }\r\n\r\n return products.every(product => \r\n product.id && \r\n product.name && \r\n typeof product.price === 'number' && \r\n product.price > 0 &&\r\n typeof product.quantity === 'number' && \r\n product.quantity > 0\r\n );\r\n}\r\n\r\n/**\r\n * 计算单个商品的单价\r\n * @param {Object} product - 商品信息\r\n * @returns {number} 单价\r\n */\r\nexport function calculateUnitPrice(product) {\r\n if (!product || !product.price || !product.quantity) {\r\n return 0;\r\n }\r\n return product.price / product.quantity;\r\n}\r\n"],"names":["PriceOptimizer","constructor","products","options","maxIterations","precision","findOptimalCombination","targetQuantity","Error","length","sortedProducts","sort","a","b","price","quantity","bestCombination","bestPrice","Infinity","i","combination","_generateCombination","totalPrice","_calculateTotalPrice","parseFloat","toFixed","unitPrice","remainingQuantity","product","maxCount","Math","ceil","count","floor","random","push","cheapestProduct","additionalCount","existingItem","find","item","id","reduce","total","addProduct","name","removeProduct","productId","filter","p","updateProduct","updates","index","findIndex","formatCurrency","amount","currency","validateProducts","Array","isArray","every","calculateUnitPrice"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "multi-product-price-optimizer",
3
+ "version": "1.0.0",
4
+ "description": "A JavaScript library for calculating optimal price combinations for multiple products",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "module": "dist/index.esm.js",
8
+ "browser": "dist/index.umd.js",
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "scripts": {
13
+ "build": "rollup -c",
14
+ "dev": "rollup -c -w",
15
+ "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
16
+ "prepublishOnly": "npm run build"
17
+ },
18
+ "keywords": [
19
+ "price",
20
+ "optimizer",
21
+ "products",
22
+ "combination",
23
+ "algorithm",
24
+ "pricing",
25
+ "cost",
26
+ "calculator",
27
+ "optimization"
28
+ ],
29
+ "author": {
30
+ "name": "Jamie",
31
+ "email": "1406526840@qq.com"
32
+ },
33
+ "license": "MIT",
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "https://github.com/zoujianmei/multi-product-price-optimizer.git"
37
+ },
38
+ "homepage": "https://github.com/zoujianmei/multi-product-price-optimizer#readme",
39
+ "bugs": {
40
+ "url": "https://github.com/zoujianmei/multi-product-price-optimizer/issues"
41
+ },
42
+ "devDependencies": {
43
+ "@babel/core": "^7.22.0",
44
+ "@babel/preset-env": "^7.22.0",
45
+ "rollup": "^3.29.0",
46
+ "@rollup/plugin-babel": "^6.0.3",
47
+ "@rollup/plugin-commonjs": "^25.0.4",
48
+ "@rollup/plugin-node-resolve": "^15.2.1",
49
+ "jest": "^29.5.0"
50
+ },
51
+ "jest": {
52
+ "testEnvironment": "node",
53
+ "transform": {}
54
+ }
55
+ }