goods-specs-popup.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. /* eslint-disable no-param-reassign */
  2. /* eslint-disable no-nested-ternary */
  3. //@ts-ignore
  4. import Toast from 'tdesign-miniprogram/toast/index'
  5. Component<
  6. {
  7. buyNum: number
  8. isAllSelectedSku: boolean
  9. },
  10. {
  11. src: ComponentPropertyStringType
  12. title: ComponentPropertyStringType
  13. show: ComponentPropertyBooleanType
  14. limitBuyInfo: ComponentPropertyStringType
  15. isStock: ComponentPropertyBooleanType
  16. limitMaxCount: ComponentPropertyNumberType
  17. limitMinCount: ComponentPropertyNumberType
  18. skuList: ComponentPropertyArrayType
  19. specList: ComponentPropertyArrayType
  20. outOperateStatus: ComponentPropertyBooleanType
  21. outEditStatus: ComponentPropertyBooleanType
  22. hasAuth: ComponentPropertyBooleanType
  23. count: ComponentPropertyNumberType
  24. },
  25. {
  26. initData(): void
  27. checkSkuStockQuantity(specValueId: number, skuList: any[]): void
  28. chooseSpecValueId(specValueId: number, specId: number): void
  29. flatten(input: any[]): any[]
  30. getIntersection(array: any[], nextArray: any[]): any[]
  31. toChooseItem(e: any): void
  32. isAllSelected(skuTree: any[], selectedSku: any[]): void
  33. handlePopupHide(): void
  34. specsConfirm(): void
  35. addCart(): void
  36. buyNow(): void
  37. handleBuyNumPlus(): void
  38. handleBuyNumMinus(): void
  39. setBuyNum(buyNum: number): void
  40. handleBuyNumChange(e: WechatMiniprogram.CustomEvent<{ value: string }>): void
  41. },
  42. {
  43. initStatus: boolean
  44. selectedSku: any
  45. selectSpecObj: any
  46. }
  47. >({
  48. options: {
  49. multipleSlots: true,
  50. addGlobalClass: true,
  51. },
  52. properties: {
  53. src: {
  54. type: String,
  55. },
  56. title: {
  57. type: String,
  58. },
  59. show: {
  60. type: Boolean,
  61. value: false,
  62. },
  63. limitBuyInfo: {
  64. type: String,
  65. value: '',
  66. },
  67. isStock: {
  68. type: Boolean,
  69. value: true,
  70. },
  71. limitMaxCount: {
  72. type: Number,
  73. value: 999,
  74. },
  75. limitMinCount: {
  76. type: Number,
  77. value: 1,
  78. },
  79. skuList: {
  80. type: Array,
  81. value: [],
  82. observer(skuList) {
  83. if (skuList && skuList.length > 0) {
  84. if (this.initStatus) {
  85. this.initData()
  86. }
  87. }
  88. },
  89. },
  90. specList: {
  91. type: Array,
  92. value: [],
  93. observer(specList) {
  94. if (specList && specList.length > 0) {
  95. this.initData()
  96. }
  97. },
  98. },
  99. outOperateStatus: {
  100. type: Boolean,
  101. value: false,
  102. },
  103. outEditStatus: {
  104. type: Boolean,
  105. value: false,
  106. },
  107. hasAuth: {
  108. type: Boolean,
  109. value: false,
  110. },
  111. count: {
  112. type: Number,
  113. value: 1,
  114. observer(count) {
  115. this.setData({
  116. buyNum: count,
  117. })
  118. },
  119. },
  120. },
  121. data: {
  122. buyNum: 1,
  123. isAllSelectedSku: false,
  124. },
  125. observers: {
  126. limitMinCount(limitMinCount) {
  127. this.setBuyNum(limitMinCount)
  128. },
  129. },
  130. lifetimes: {
  131. created() {
  132. this.initStatus = false
  133. this.selectedSku = {}
  134. this.selectSpecObj = {}
  135. },
  136. ready() {
  137. console.log(this.data.skuList, this.data.specList)
  138. },
  139. },
  140. methods: {
  141. initData() {
  142. const { skuList } = this.properties
  143. const { specList } = this.properties
  144. specList.forEach((item) => {
  145. if (item.specValueList.length > 0) {
  146. item.specValueList.forEach((subItem) => {
  147. const obj = this.checkSkuStockQuantity(subItem.specValueId, skuList)
  148. subItem.hasStockObj = obj
  149. })
  150. }
  151. })
  152. const selectedSku = {}
  153. specList.forEach((item) => {
  154. selectedSku[item.specId] = ''
  155. })
  156. this.setData({
  157. specList,
  158. })
  159. this.selectSpecObj = {}
  160. this.selectedSku = {}
  161. this.initStatus = true
  162. },
  163. checkSkuStockQuantity(specValueId, skuList) {
  164. let hasStock = false
  165. const array = []
  166. skuList.forEach((item) => {
  167. ;(item.specInfo || []).forEach((subItem) => {
  168. if (subItem.specValueId === specValueId && item.quantity > 0) {
  169. const subArray = []
  170. ;(item.specInfo || []).forEach((specItem) => {
  171. subArray.push(specItem.specValueId)
  172. })
  173. array.push(subArray)
  174. hasStock = true
  175. }
  176. })
  177. })
  178. return {
  179. hasStock,
  180. specsArray: array,
  181. }
  182. },
  183. chooseSpecValueId(specValueId, specId) {
  184. const { selectSpecObj } = this
  185. const { skuList, specList } = this.properties
  186. if (selectSpecObj[specId]) {
  187. selectSpecObj[specId] = []
  188. this.selectSpecObj = selectSpecObj
  189. } else {
  190. selectSpecObj[specId] = []
  191. }
  192. const itemAllSpecArray = []
  193. const itemUnSelectArray = []
  194. const itemSelectArray = []
  195. specList.forEach((item) => {
  196. if (item.specId === specId) {
  197. const subSpecValueItem = item.specValueList.find(
  198. (subItem) => subItem.specValueId === specValueId,
  199. )
  200. let specSelectStatus = false
  201. item.specValueList.forEach((n) => {
  202. itemAllSpecArray.push(n.hasStockObj.specsArray)
  203. if (n.isChoosed) {
  204. specSelectStatus = true
  205. }
  206. if (n.hasStockObj.hasStock) {
  207. itemSelectArray.push(n.specValueId)
  208. } else {
  209. itemUnSelectArray.push(n.specValueId)
  210. }
  211. })
  212. if (specSelectStatus) {
  213. selectSpecObj[specId] = this.flatten(
  214. subSpecValueItem?.hasStockObj.specsArray.concat(itemSelectArray),
  215. )
  216. } else {
  217. const subSet = function (arr1, arr2) {
  218. const set2 = new Set(arr2)
  219. const subset = []
  220. arr1.forEach((val) => {
  221. if (!set2.has(val)) {
  222. subset.push(val)
  223. }
  224. })
  225. return subset
  226. }
  227. selectSpecObj[specId] = subSet(
  228. this.flatten(itemAllSpecArray),
  229. this.flatten(itemUnSelectArray),
  230. )
  231. }
  232. } else {
  233. // 未点击规格的逻辑
  234. const itemSelectArray = []
  235. let specSelectStatus = false
  236. item.specValueList.map(
  237. // 找到有库存的规格数组
  238. (n) => {
  239. itemSelectArray.push(n.hasStockObj.specsArray)
  240. if (n.isChoosed) {
  241. specSelectStatus = true
  242. }
  243. n.hasStockObj.hasStock = true
  244. return n
  245. },
  246. )
  247. if (specSelectStatus) {
  248. selectSpecObj[item.specId] = this.flatten(itemSelectArray)
  249. } else {
  250. delete selectSpecObj[item.specId]
  251. }
  252. }
  253. this.selectSpecObj = selectSpecObj
  254. })
  255. const combatArray = Object.values(selectSpecObj)
  256. if (combatArray.length > 0) {
  257. const showArray = combatArray.reduce((x, y) => this.getIntersection(x, y))
  258. const lastResult = Array.from(new Set(showArray))
  259. specList.forEach((item) => {
  260. item.specValueList.forEach((subItem) => {
  261. if (lastResult.includes(subItem.specValueId)) {
  262. subItem.hasStockObj.hasStock = true
  263. } else {
  264. subItem.hasStockObj.hasStock = false
  265. }
  266. })
  267. })
  268. } else {
  269. specList.forEach((item) => {
  270. if (item.specValueList.length > 0) {
  271. item.specValueList.forEach((subItem) => {
  272. const obj = this.checkSkuStockQuantity(subItem.specValueId, skuList)
  273. subItem.hasStockObj = obj
  274. })
  275. }
  276. })
  277. }
  278. this.setData({
  279. specList,
  280. })
  281. },
  282. flatten(input) {
  283. const stack = [...input]
  284. const res = []
  285. while (stack.length) {
  286. const next = stack.pop()
  287. if (Array.isArray(next)) {
  288. stack.push(...next)
  289. } else {
  290. res.push(next)
  291. }
  292. }
  293. return res.reverse()
  294. },
  295. getIntersection(array, nextArray) {
  296. return array.filter((item) => nextArray.includes(item))
  297. },
  298. toChooseItem(e) {
  299. const { isStock } = this.properties
  300. if (!isStock) return
  301. const { id } = e.currentTarget.dataset
  302. const specId = e.currentTarget.dataset.specid
  303. const hasStock = e.currentTarget.dataset.hasstock
  304. if (!hasStock) {
  305. Toast({
  306. context: this,
  307. selector: '#t-toast',
  308. message: '该规格已售罄',
  309. icon: '',
  310. duration: 1000,
  311. })
  312. return
  313. }
  314. let { selectedSku } = this
  315. const { specList } = this.properties
  316. selectedSku =
  317. selectedSku[specId] === id
  318. ? { ...this.selectedSku, [specId]: '' }
  319. : { ...this.selectedSku, [specId]: id }
  320. specList.forEach((item) => {
  321. item.specValueList.forEach((valuesItem) => {
  322. if (item.specId === specId) {
  323. valuesItem.isChoosed = valuesItem.specValueId === selectedSku[specId]
  324. }
  325. })
  326. })
  327. this.chooseSpecValueId(id, specId)
  328. const isAllSelectedSku = this.isAllSelected(specList, selectedSku)
  329. if (!isAllSelectedSku) {
  330. this.setData({
  331. selectSkuSellsPrice: 0,
  332. selectSkuImg: '',
  333. })
  334. }
  335. this.setData({
  336. specList,
  337. isAllSelectedSku,
  338. })
  339. this.selectedSku = selectedSku
  340. this.triggerEvent('change', {
  341. specList,
  342. selectedSku,
  343. isAllSelectedSku,
  344. })
  345. },
  346. // 判断是否所有的sku都已经选中
  347. isAllSelected(skuTree, selectedSku) {
  348. const selected = Object.keys(selectedSku).filter((skuKeyStr) => selectedSku[skuKeyStr] !== '')
  349. return skuTree.length === selected.length
  350. },
  351. handlePopupHide() {
  352. this.triggerEvent('closeSpecsPopup', {
  353. show: false,
  354. })
  355. },
  356. specsConfirm() {
  357. const { isStock, isAllSelectedSku, buyNum } = this.properties
  358. if (!isStock) {
  359. return
  360. }
  361. if (!isAllSelectedSku) {
  362. Toast({
  363. context: this,
  364. selector: '#t-toast',
  365. message: '请选择规格',
  366. icon: '',
  367. duration: 1000,
  368. })
  369. return
  370. }
  371. this.triggerEvent('specsConfirm', {
  372. buy: buyNum,
  373. })
  374. },
  375. addCart() {
  376. const { isStock } = this.properties
  377. if (!isStock) return
  378. this.triggerEvent('addCart')
  379. },
  380. buyNow() {
  381. const { isAllSelectedSku } = this.data
  382. const { isStock } = this.properties
  383. if (!isStock) return
  384. this.triggerEvent('buyNow', {
  385. isAllSelectedSku,
  386. })
  387. },
  388. // 加
  389. handleBuyNumPlus() {
  390. const { buyNum } = this.data
  391. const { isStock, limitMaxCount } = this.properties
  392. if (!isStock) return
  393. const nextBuyNum = Number(buyNum) + 1
  394. this.setBuyNum(Math.min(limitMaxCount, nextBuyNum > 999 ? buyNum : nextBuyNum))
  395. },
  396. // 减
  397. handleBuyNumMinus() {
  398. const { buyNum } = this.data
  399. const { limitMinCount } = this.properties
  400. const { isStock } = this.properties
  401. if (!isStock) return
  402. const nextBuyNum = Number(buyNum) - 1
  403. this.setBuyNum(Math.max(limitMinCount, nextBuyNum < 1 ? buyNum : nextBuyNum))
  404. },
  405. // 总处理
  406. setBuyNum(buyNum) {
  407. this.setData({
  408. buyNum,
  409. })
  410. this.triggerEvent('changeNum', {
  411. buyNum,
  412. })
  413. },
  414. // 输入框
  415. handleBuyNumChange(e) {
  416. const {
  417. detail: { value },
  418. } = e
  419. const valInNum = Number(value)
  420. const { limitMaxCount, limitMinCount } = this.properties
  421. const nextData = {
  422. buyNum:
  423. valInNum < limitMinCount
  424. ? limitMinCount
  425. : valInNum > limitMaxCount
  426. ? limitMaxCount
  427. : valInNum,
  428. }
  429. this.setData(nextData)
  430. },
  431. },
  432. })