index.js 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. /* eslint-disable no-param-reassign */
  2. /* eslint-disable no-nested-ternary */
  3. import Toast from 'tdesign-miniprogram/toast/index';
  4. Component({
  5. options: {
  6. multipleSlots: true,
  7. addGlobalClass: true,
  8. },
  9. properties: {
  10. src: {
  11. type: String,
  12. },
  13. title: String,
  14. show: {
  15. type: Boolean,
  16. value: false,
  17. },
  18. limitBuyInfo: {
  19. type: String,
  20. value: '',
  21. },
  22. isStock: {
  23. type: Boolean,
  24. value: true,
  25. },
  26. limitMaxCount: {
  27. type: Number,
  28. value: 999,
  29. },
  30. limitMinCount: {
  31. type: Number,
  32. value: 1,
  33. },
  34. skuList: {
  35. type: Array,
  36. value: [],
  37. observer(skuList) {
  38. if (skuList && skuList.length > 0) {
  39. if (this.initStatus) {
  40. this.initData();
  41. }
  42. }
  43. },
  44. },
  45. specList: {
  46. type: Array,
  47. value: [],
  48. observer(specList) {
  49. if (specList && specList.length > 0) {
  50. this.initData();
  51. }
  52. },
  53. },
  54. outOperateStatus: {
  55. type: Boolean,
  56. value: false,
  57. },
  58. hasAuth: {
  59. type: Boolean,
  60. value: false,
  61. },
  62. count: {
  63. type: Number,
  64. value: 1,
  65. observer(count) {
  66. this.setData({
  67. buyNum: count,
  68. });
  69. },
  70. },
  71. },
  72. initStatus: false,
  73. selectedSku: {},
  74. selectSpecObj: {},
  75. data: {
  76. buyNum: 1,
  77. isAllSelectedSku: false,
  78. },
  79. methods: {
  80. initData() {
  81. const { skuList } = this.properties;
  82. const { specList } = this.properties;
  83. specList.forEach((item) => {
  84. if (item.specValueList.length > 0) {
  85. item.specValueList.forEach((subItem) => {
  86. const obj = this.checkSkuStockQuantity(subItem.specValueId, skuList);
  87. subItem.hasStockObj = obj;
  88. });
  89. }
  90. });
  91. const selectedSku = {};
  92. specList.forEach((item) => {
  93. selectedSku[item.specId] = '';
  94. });
  95. this.setData({
  96. specList,
  97. });
  98. this.selectSpecObj = {};
  99. this.selectedSku = {};
  100. this.initStatus = true;
  101. },
  102. checkSkuStockQuantity(specValueId, skuList) {
  103. let hasStock = false;
  104. const array = [];
  105. skuList.forEach((item) => {
  106. (item.specInfo || []).forEach((subItem) => {
  107. if (subItem.specValueId === specValueId && item.quantity > 0) {
  108. const subArray = [];
  109. (item.specInfo || []).forEach((specItem) => {
  110. subArray.push(specItem.specValueId);
  111. });
  112. array.push(subArray);
  113. hasStock = true;
  114. }
  115. });
  116. });
  117. return {
  118. hasStock,
  119. specsArray: array,
  120. };
  121. },
  122. chooseSpecValueId(specValueId, specId) {
  123. const { selectSpecObj } = this;
  124. const { skuList, specList } = this.properties;
  125. if (selectSpecObj[specId]) {
  126. selectSpecObj[specId] = [];
  127. this.selectSpecObj = selectSpecObj;
  128. } else {
  129. selectSpecObj[specId] = [];
  130. }
  131. const itemAllSpecArray = [];
  132. const itemUnSelectArray = [];
  133. const itemSelectArray = [];
  134. specList.forEach((item) => {
  135. if (item.specId === specId) {
  136. const subSpecValueItem = item.specValueList.find((subItem) => subItem.specValueId === specValueId);
  137. let specSelectStatus = false;
  138. item.specValueList.forEach((n) => {
  139. itemAllSpecArray.push(n.hasStockObj.specsArray);
  140. if (n.isSelected) {
  141. specSelectStatus = true;
  142. }
  143. if (n.hasStockObj.hasStock) {
  144. itemSelectArray.push(n.specValueId);
  145. } else {
  146. itemUnSelectArray.push(n.specValueId);
  147. }
  148. });
  149. if (specSelectStatus) {
  150. selectSpecObj[specId] = this.flatten(subSpecValueItem?.hasStockObj.specsArray.concat(itemSelectArray));
  151. } else {
  152. const subSet = function (arr1, arr2) {
  153. const set2 = new Set(arr2);
  154. const subset = [];
  155. arr1.forEach((val) => {
  156. if (!set2.has(val)) {
  157. subset.push(val);
  158. }
  159. });
  160. return subset;
  161. };
  162. selectSpecObj[specId] = subSet(this.flatten(itemAllSpecArray), this.flatten(itemUnSelectArray));
  163. }
  164. } else {
  165. // 未点击规格的逻辑
  166. const itemSelectArray = [];
  167. let specSelectStatus = false;
  168. item.specValueList.map(
  169. // 找到有库存的规格数组
  170. (n) => {
  171. itemSelectArray.push(n.hasStockObj.specsArray);
  172. if (n.isSelected) {
  173. specSelectStatus = true;
  174. }
  175. n.hasStockObj.hasStock = true;
  176. return n;
  177. },
  178. );
  179. if (specSelectStatus) {
  180. selectSpecObj[item.specId] = this.flatten(itemSelectArray);
  181. } else {
  182. delete selectSpecObj[item.specId];
  183. }
  184. }
  185. this.selectSpecObj = selectSpecObj;
  186. });
  187. const combatArray = Object.values(selectSpecObj);
  188. if (combatArray.length > 0) {
  189. const showArray = combatArray.reduce((x, y) => this.getIntersection(x, y));
  190. const lastResult = Array.from(new Set(showArray));
  191. specList.forEach((item) => {
  192. item.specValueList.forEach((subItem) => {
  193. if (lastResult.includes(subItem.specValueId)) {
  194. subItem.hasStockObj.hasStock = true;
  195. } else {
  196. subItem.hasStockObj.hasStock = false;
  197. }
  198. });
  199. });
  200. } else {
  201. specList.forEach((item) => {
  202. if (item.specValueList.length > 0) {
  203. item.specValueList.forEach((subItem) => {
  204. const obj = this.checkSkuStockQuantity(subItem.specValueId, skuList);
  205. subItem.hasStockObj = obj;
  206. });
  207. }
  208. });
  209. }
  210. this.setData({
  211. specList,
  212. });
  213. },
  214. flatten(input) {
  215. const stack = [...input];
  216. const res = [];
  217. while (stack.length) {
  218. const next = stack.pop();
  219. if (Array.isArray(next)) {
  220. stack.push(...next);
  221. } else {
  222. res.push(next);
  223. }
  224. }
  225. return res.reverse();
  226. },
  227. getIntersection(array, nextArray) {
  228. return array.filter((item) => nextArray.includes(item));
  229. },
  230. toChooseItem(e) {
  231. const { isStock } = this.properties;
  232. if (!isStock) return;
  233. const { id } = e.currentTarget.dataset;
  234. const specId = e.currentTarget.dataset.specid;
  235. const hasStock = e.currentTarget.dataset.hasstock;
  236. if (!hasStock) {
  237. Toast({
  238. context: this,
  239. selector: '#t-toast',
  240. message: '该规格已售罄',
  241. icon: '',
  242. duration: 1000,
  243. });
  244. return;
  245. }
  246. let { selectedSku } = this;
  247. const { specList } = this.properties;
  248. selectedSku =
  249. selectedSku[specId] === id ? { ...this.selectedSku, [specId]: '' } : { ...this.selectedSku, [specId]: id };
  250. specList.forEach((item) => {
  251. item.specValueList.forEach((valuesItem) => {
  252. if (item.specId === specId) {
  253. valuesItem.isSelected = valuesItem.specValueId === selectedSku[specId];
  254. }
  255. });
  256. });
  257. this.chooseSpecValueId(id, specId);
  258. const isAllSelectedSku = this.isAllSelected(specList, selectedSku);
  259. if (!isAllSelectedSku) {
  260. this.setData({
  261. selectSkuSellsPrice: 0,
  262. selectSkuImg: '',
  263. });
  264. }
  265. this.setData({
  266. specList,
  267. isAllSelectedSku,
  268. });
  269. this.selectedSku = selectedSku;
  270. this.triggerEvent('change', {
  271. specList,
  272. selectedSku,
  273. isAllSelectedSku,
  274. });
  275. },
  276. // 判断是否所有的sku都已经选中
  277. isAllSelected(skuTree, selectedSku) {
  278. const selected = Object.keys(selectedSku).filter((skuKeyStr) => selectedSku[skuKeyStr] !== '');
  279. return skuTree.length === selected.length;
  280. },
  281. handlePopupHide() {
  282. this.triggerEvent('closeSpecsPopup', {
  283. show: false,
  284. });
  285. },
  286. specsConfirm() {
  287. const { isStock } = this.properties;
  288. if (!isStock) return;
  289. this.triggerEvent('specsConfirm');
  290. },
  291. addCart() {
  292. const { isStock } = this.properties;
  293. if (!isStock) return;
  294. this.triggerEvent('addCart');
  295. },
  296. buyNow() {
  297. const { isAllSelectedSku } = this.data;
  298. const { isStock } = this.properties;
  299. if (!isStock) return;
  300. this.triggerEvent('buyNow', {
  301. isAllSelectedSku,
  302. });
  303. },
  304. // 总处理
  305. setBuyNum(buyNum) {
  306. this.setData({
  307. buyNum,
  308. });
  309. this.triggerEvent('changeNum', {
  310. buyNum,
  311. });
  312. },
  313. handleBuyNumChange(e) {
  314. const { value } = e.detail;
  315. this.setData({
  316. buyNum: value,
  317. });
  318. },
  319. },
  320. });