index.ts 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  1. //@ts-ignore
  2. import Toast from 'tdesign-miniprogram/toast/index'
  3. import GoodApi from '../../../services/good'
  4. import Navi from '../../../utils/navi'
  5. import { backPage, getCurrentUrl, isLogin, obj2Params, saveToAlbum } from '../../../utils/util'
  6. // pages/goods/detail/index.ts
  7. Page({
  8. /**
  9. * 页面的初始数据
  10. */
  11. data: {
  12. id: -1,
  13. cateid: -1,
  14. downloading: false,
  15. guidshow: false,
  16. nodraws: true,
  17. drawshow: false,
  18. selectedAttrStr: '',
  19. buyType: 0,
  20. addingCart: false,
  21. // 猜你喜欢
  22. favList: [] as WxGetCateAlbumOutput[],
  23. favTotal: 0,
  24. loadMoreStatus: 0,
  25. albumInput: {
  26. skipCount: 0,
  27. maxResultCount: 10,
  28. },
  29. // 评论
  30. commentsDto: {},
  31. commentsStatistics: {
  32. commentCount: 0,
  33. hasImageCount: 0,
  34. goodRate: 0,
  35. goodCount: 0,
  36. middleCount: 0,
  37. badCount: 0,
  38. },
  39. // 内容分类
  40. goodsTabArray: [],
  41. details: {} as WxGetProductOutput,
  42. loading: true,
  43. // 底部栏目
  44. jumpArray: [
  45. {
  46. title: '购物袋',
  47. url: '/pages/cart/index',
  48. iconName: 'ibag-bold',
  49. showCartNum: true,
  50. switchTab: true,
  51. prefix: 'hn',
  52. },
  53. {
  54. title: '收藏',
  55. selected: false,
  56. fav: false,
  57. prefix: 'hn',
  58. iconName: 'cshoucang',
  59. selectedIconName: 'cshoucang-filled',
  60. },
  61. ],
  62. // 店铺信息
  63. storeId: 0,
  64. storeLogo: '',
  65. storeName: '',
  66. storeImag: '',
  67. selectItem: null as {
  68. skuId: number
  69. quantity: number
  70. image: string
  71. price: number
  72. linePrice: number
  73. specInfo: []
  74. } | null,
  75. // 优惠活动
  76. activityList: [],
  77. isShowActivityList: false,
  78. // 商品信息
  79. promotionArray: [] as {
  80. tag: ''
  81. value: number
  82. label: ''
  83. }[],
  84. skuArray: [] as {
  85. skuId: number
  86. quantity: number
  87. image: string
  88. price: number
  89. linePrice: number
  90. specInfo: []
  91. }[],
  92. primaryImage: '', // 产品图
  93. selectSkuImage: '', // 选择产品图
  94. selectSkuSalePrice: 0, // 选择产品图
  95. selectSkuLinePrice: 0, // 选择产品图
  96. selectSkuName: '', // 选择产品图
  97. isAllSkuSelected: false,
  98. selectedSkuAttrStr: '', // 当前选择的 SKU 内容
  99. isSpuSelectPopupShow: false, // SKU弹窗状态
  100. isAllSelectedSku: false, // 是否已选择所有SKU信息
  101. buyNum: 0,
  102. buttonType: 1,
  103. isStock: true, // 是否有库存
  104. soldout: false, // 是否可售
  105. soldNum: 0, // 已售数量
  106. unit: '',
  107. minSalePrice: 0,
  108. minLinePrice: 0,
  109. maxSalePrice: 0,
  110. limitMaxCount: 999,
  111. limitMinCount: 1,
  112. limitBuyInfo: '',
  113. // 轮播组件
  114. navigation: { type: 'dots-bar' },
  115. autoplay: false,
  116. duration: 500,
  117. interval: 5000,
  118. swipepics: [] as string[],
  119. swipewidth: '750rpx',
  120. swipeheight: '506rpx',
  121. imgSrcs: [
  122. { img: 'https://cdn-we-retail.ym.tencent.com/tsr/home/v2/banner1.png', text: '1' },
  123. { img: 'https://cdn-we-retail.ym.tencent.com/tsr/home/v2/banner2.png', text: '2' },
  124. { img: 'https://cdn-we-retail.ym.tencent.com/tsr/home/v2/banner3.png', text: '3' },
  125. { img: 'https://cdn-we-retail.ym.tencent.com/tsr/home/v2/banner4.png', text: '4' },
  126. { img: 'https://cdn-we-retail.ym.tencent.com/tsr/home/v2/banner5.png', text: '5' },
  127. { img: 'https://cdn-we-retail.ym.tencent.com/tsr/home/v2/banner6.png', text: '6' },
  128. ],
  129. },
  130. handleAuthDisagree() {
  131. backPage()
  132. },
  133. handleAuthOK() {
  134. console.log('check it', this.data)
  135. this.init()
  136. },
  137. init() {
  138. const id = this.data.id
  139. const cateid = this.data.cateid
  140. console.log('dd', id, cateid)
  141. GoodApi.GetProduct({ id, cateid } as any).then((rsp) => {
  142. if (rsp.result) {
  143. const details = rsp.result
  144. const {
  145. imageUrl: primaryImage,
  146. soldNum,
  147. limitMaxCount,
  148. limitMinCount,
  149. limitBuyInfo,
  150. unit,
  151. } = details
  152. const skuArray = [] as {
  153. skuId: number
  154. quantity: number
  155. image: string
  156. price: number
  157. linePrice: number
  158. specInfo: TmpSpecInfo[]
  159. }[]
  160. if (details.skuList) {
  161. details.skuList.forEach((item) => {
  162. const priceInfo = item.priceInfo || []
  163. const len = priceInfo.length
  164. skuArray.push({
  165. skuId: Number(item.skuId),
  166. image: item.skuImage || primaryImage || '',
  167. price: len > 0 ? priceInfo[0].price : 0,
  168. linePrice: len > 1 ? priceInfo[1].price : 0,
  169. quantity: item.stockInfo ? item.stockInfo.stockQuantity : 0,
  170. specInfo: item.specInfo || [],
  171. })
  172. })
  173. }
  174. let pics = []
  175. if (rsp.result.imageUrl) {
  176. pics.push(rsp.result.imageUrl)
  177. }
  178. if (rsp.result.images && rsp.result.images.length > 0) {
  179. pics = pics.concat(rsp.result.images)
  180. }
  181. const hasDraw =
  182. (details.draws && details.draws.length > 0) ||
  183. (details.draws2D && details.draws2D.length > 0)
  184. this.setData({
  185. details,
  186. nodraws: !hasDraw,
  187. swipepics: pics,
  188. current: 0,
  189. loading: false,
  190. primaryImage,
  191. isStock: details.spuStockQuantity > 0,
  192. maxSalePrice: details.maxSalePrice,
  193. maxLinePrice: details.maxLinePrice,
  194. minSalePrice: details.minSalePrice,
  195. minLinePrice: details.minLinePrice,
  196. skuArray: skuArray as any,
  197. soldout: details.isPutOnSale === 0,
  198. soldNum,
  199. limitMaxCount,
  200. limitMinCount,
  201. limitBuyInfo,
  202. unit,
  203. })
  204. this.setFav(rsp.result.isFav)
  205. wx.setNavigationBarTitle({
  206. title: rsp.result.title || '',
  207. })
  208. console.log(rsp.result)
  209. }
  210. })
  211. // GoodApi.GetFav({ id, cateId: cateid }).then((rsp) => {
  212. // if (rsp.result && rsp.result.length > 0) {
  213. // this.setData({
  214. // favList: rsp.result,
  215. // })
  216. // }
  217. // })
  218. GoodApi.GetComments({ id }).then((rsp) => {
  219. if (rsp.result) {
  220. this.setData({
  221. commentsDto: rsp.result,
  222. })
  223. }
  224. })
  225. this.loadRecommend(true)
  226. },
  227. loadRecommend(rest = false) {
  228. console.log('next')
  229. this.setData({
  230. loadMoreStatus: 1,
  231. })
  232. GoodApi.GetHomeRecommend(this.data.albumInput as any).then((rsp) => {
  233. if (rsp.result) {
  234. const result = rsp.result as any
  235. const { items = [] } = result
  236. const nowItems = rest ? items : this.data.favList.concat(items)
  237. this.setData({
  238. favList: nowItems as any,
  239. favTotal: result.totalCount || 0,
  240. loadMoreStatus: nowItems.length === result.totalCount ? 2 : 0,
  241. })
  242. }
  243. })
  244. },
  245. handleReachBottom() {
  246. if (this.data.loadMoreStatus === 0 && this.data.favList.length < this.data.favTotal) {
  247. this.setData(
  248. {
  249. albumInput: {
  250. ...this.data.albumInput,
  251. skipCount: this.data.albumInput.skipCount + 10,
  252. },
  253. },
  254. () => {
  255. this.loadRecommend()
  256. },
  257. )
  258. }
  259. },
  260. /**
  261. * 生命周期函数--监听页面加载
  262. */
  263. onLoad(query: Record<string, string>) {
  264. console.log('onload')
  265. const { id, cateid } = query
  266. this.setData({
  267. id: Number(id),
  268. cateid: Number(cateid),
  269. })
  270. },
  271. /**
  272. * 生命周期函数--监听页面初次渲染完成
  273. */
  274. onReady() {},
  275. /**
  276. * 生命周期函数--监听页面显示
  277. */
  278. onShow() {},
  279. /**
  280. * 生命周期函数--监听页面隐藏
  281. */
  282. onHide() {},
  283. /**
  284. * 生命周期函数--监听页面卸载
  285. */
  286. onUnload() {},
  287. /**
  288. * 页面相关事件处理函数--监听用户下拉动作
  289. */
  290. onPullDownRefresh() {},
  291. /**
  292. * 页面上拉触底事件的处理函数
  293. */
  294. onReachBottom() {},
  295. /**
  296. * 用户点击右上角分享
  297. */
  298. onShareAppMessage(e: WechatMiniprogram.Page.IShareAppMessageOption) {
  299. console.log(e, 'ssss')
  300. // const promise = new Promise((resolve) => {
  301. // setTimeout(() => {
  302. // resolve({
  303. // title: '自定义转发标题',
  304. // })
  305. // }, 2000)
  306. // })
  307. const url = getCurrentUrl()
  308. return {
  309. title: this.data.details.title,
  310. path: url,
  311. imageUrl: this.data.swipepics[0],
  312. //promise,
  313. }
  314. },
  315. onPreview(e: WechatMiniprogram.BaseEvent<{ idx: number }>) {
  316. const { idx = 0 } = e.currentTarget.dataset
  317. wx.previewImage({
  318. urls: this.data.swipepics,
  319. current: this.data.swipepics[idx],
  320. })
  321. },
  322. gotoGoodsDetail(e: WechatMiniprogram.CustomEvent<{ goods: WxCateAlbumItemDto; index: number }>) {
  323. const { goods } = e.detail
  324. Navi.redirectTo({
  325. url: '/pages/goods/detail/index?id=' + goods.id + '&cateid=' + this.data.cateid,
  326. })
  327. },
  328. /**
  329. *
  330. */
  331. chooseSpecItem(
  332. e: WechatMiniprogram.CustomEvent<{
  333. selectedSku: Record<string, string>
  334. isAllSelectedSku: boolean
  335. }>,
  336. ) {
  337. const { specList } = this.data.details
  338. const { selectedSku, isAllSelectedSku } = e.detail
  339. console.log(specList, isAllSelectedSku, selectedSku)
  340. if (!isAllSelectedSku) {
  341. this.setData({
  342. selectSkuSellPrice: 0,
  343. })
  344. }
  345. this.setData({
  346. isAllSelectedSku,
  347. })
  348. this.getSkuItem(specList, selectedSku)
  349. },
  350. getSkuItem(specList: TmpSpec[] | undefined, selectedSku: Record<string, string>) {
  351. const { skuArray, primaryImage, unit } = this.data
  352. const selectedSkuValues = this.getSelectedSkuValues(specList, selectedSku)
  353. let selectedAttrStr = ` ${unit} `
  354. selectedSkuValues.forEach((item) => {
  355. selectedAttrStr += `,${item.specValue} `
  356. })
  357. // eslint-disable-next-line array-callback-return
  358. const findSkuItem = skuArray.filter((item) => {
  359. let status = true
  360. ;(item.specInfo || []).forEach((subItem) => {
  361. if (!selectedSku[subItem.specId] || selectedSku[subItem.specId] !== subItem.specValueId) {
  362. status = false
  363. }
  364. })
  365. if (status) return item
  366. })
  367. this.selectSpecsName(selectedSkuValues.length > 0 ? selectedAttrStr : '')
  368. console.log('find sku:', findSkuItem)
  369. if (findSkuItem && findSkuItem.length > 0) {
  370. const selectItem = findSkuItem[0]
  371. this.setData({
  372. specImg: selectItem.image,
  373. selectItem,
  374. selectSkuSellPrice: selectItem.price || 0,
  375. selectSkuLinePrice: selectItem.linePrice || 0,
  376. })
  377. } else {
  378. this.setData({
  379. specImg: primaryImage,
  380. selectItem: null,
  381. selectSkuSellPrice: 0,
  382. selectSkuLinePrice: 0,
  383. })
  384. }
  385. },
  386. getSelectedSkuValues(skuTree, selectedSku) {
  387. const normalizedTree = this.normalizeSkuTree(skuTree)
  388. return Object.keys(selectedSku).reduce((selectedValues, skuKeyStr) => {
  389. const skuValues = normalizedTree[skuKeyStr]
  390. const skuValueId = selectedSku[skuKeyStr]
  391. if (skuValueId !== '') {
  392. const skuValue = skuValues.filter((value) => {
  393. return value.specValueId === skuValueId
  394. })[0]
  395. skuValue && selectedValues.push(skuValue)
  396. }
  397. return selectedValues
  398. }, [])
  399. },
  400. normalizeSkuTree(skuTree) {
  401. const normalizedTree = {}
  402. skuTree.forEach((treeItem) => {
  403. normalizedTree[treeItem.specId] = treeItem.specValueList
  404. })
  405. return normalizedTree
  406. },
  407. selectSpecsName(selectSpecsName: string) {
  408. if (selectSpecsName) {
  409. this.setData({
  410. selectedAttrStr: selectSpecsName,
  411. })
  412. } else {
  413. this.setData({
  414. selectedAttrStr: '',
  415. })
  416. }
  417. },
  418. /**
  419. * SPU 选择器
  420. */
  421. handlePopupHide() {
  422. this.setData({
  423. isSpuSelectPopupShow: false,
  424. })
  425. },
  426. showSkuSelectPopup(type: number) {
  427. console.log(type)
  428. this.setData({
  429. buyType: type || 0,
  430. outOperateStatus: type >= 1,
  431. isSpuSelectPopupShow: true,
  432. })
  433. },
  434. toAddCart() {
  435. this.showSkuSelectPopup(2)
  436. },
  437. specsConfirm(e: WechatMiniprogram.CustomEvent<{ buy: number }>) {
  438. const { buy } = e.detail
  439. this.setData(
  440. {
  441. buyNum: buy,
  442. },
  443. () => {
  444. this.addCart()
  445. this.handlePopupHide()
  446. },
  447. )
  448. },
  449. setFav(state: boolean) {
  450. const arr = JSON.parse(JSON.stringify(this.data.jumpArray))
  451. arr[1].fav = state
  452. arr[1].selected = state
  453. this.setData({
  454. jumpArray: arr,
  455. })
  456. },
  457. toNav(e: WechatMiniprogram.CustomEvent<{ index: number; url: string }>) {
  458. const { index } = e.detail
  459. const node = this.data.jumpArray[index]
  460. const url = node.url
  461. if (url && url.length > 0) {
  462. if (node.switchTab) {
  463. wx.switchTab({
  464. url,
  465. })
  466. } else {
  467. wx.navigateTo({
  468. url,
  469. })
  470. }
  471. return
  472. }
  473. if (node.title === '收藏') {
  474. const state = node.fav === true ? false : true
  475. GoodApi.UpdateFav({ id: this.data.id, state }).then((rsp) => {
  476. this.setFav(state)
  477. })
  478. }
  479. console.log(node)
  480. },
  481. addCart() {
  482. const { isAllSelectedSku, selectItem, buyNum } = this.data
  483. // skuId: 154
  484. // specInfo: Array(2)
  485. // 0: {specId: 58, specTitle: null, specValueId: 170, specValue: "AL002黑色(铝合金框)", image: null}
  486. // 1: {specId: 59, specTitle: null, specValueId: 175, specValue: "80*120cm", image: null}
  487. if (selectItem) {
  488. const bag: WxAddCartInput = {
  489. cateId: this.data.cateid,
  490. goodId: this.data.id,
  491. skuId: selectItem.skuId,
  492. info: selectItem.specInfo.map((o: any) => o.specValueId),
  493. buyNum,
  494. } as any
  495. this.setData({
  496. addingCart: true,
  497. })
  498. GoodApi.AddCart(bag)
  499. .then((rsp) => {
  500. if (rsp.result === 'ok') {
  501. Toast({
  502. context: this,
  503. selector: '#t-toast',
  504. message: '已添加购物车',
  505. icon: '',
  506. duration: 1000,
  507. })
  508. }
  509. })
  510. .catch((e) => {
  511. console.log(e)
  512. Toast({
  513. context: this,
  514. selector: '#t-toast',
  515. message: '添加购物车不成功',
  516. icon: '',
  517. duration: 1000,
  518. })
  519. })
  520. .finally(() => {
  521. this.setData({
  522. addingCart: false,
  523. })
  524. })
  525. }
  526. },
  527. gotoDraw() {
  528. console.log('hihihi')
  529. this.setData({
  530. drawshow: true,
  531. })
  532. },
  533. gotoFly(e: WechatMiniprogram.BaseEvent<{}, { type: string }>) {
  534. const type = e.currentTarget.dataset.type
  535. let can = false
  536. let id = -1
  537. if (type === 'flat' && this.data.details.draws2D && this.data.details.draws2D.length > 0) {
  538. can = true
  539. id = this.data.details.draws2D[0].id
  540. } else if (type === 'space' && this.data.details.draws && this.data.details.draws.length > 0) {
  541. can = true
  542. id = this.data.details.draws[0].id
  543. }
  544. if (can) {
  545. GoodApi.GetDrawLink({
  546. id: id,
  547. goodId: this.data.id,
  548. type,
  549. }).then((rsp) => {
  550. if (rsp.result && rsp.result.length > 0) {
  551. console.log('navi')
  552. Navi.navigateTo({
  553. url: '/pages/outlink/index?url=' + encodeURIComponent(rsp.result),
  554. })
  555. }
  556. })
  557. }
  558. },
  559. handleDrawPopupHide() {
  560. this.setData({
  561. drawshow: false,
  562. })
  563. },
  564. gotoComments() {
  565. let urlQueryStr = obj2Params({
  566. spuId: this.data.id,
  567. gid: this.data.gid,
  568. } as any)
  569. urlQueryStr = urlQueryStr ? `?${urlQueryStr}` : ''
  570. const path = `/pages/goods/comments/index${urlQueryStr}`
  571. wx.navigateTo({
  572. url: path,
  573. })
  574. },
  575. onSwipeChange(e: WechatMiniprogram.CustomEvent<{ current: number }>) {
  576. const { current } = e.detail
  577. this.setData({
  578. current,
  579. })
  580. },
  581. gotoshare() {},
  582. gotodownload() {
  583. this.setData({
  584. downloading: true,
  585. })
  586. saveToAlbum(this.data.swipepics[0])
  587. .then((step: Number) => {
  588. if (step === 1) {
  589. this.setData({
  590. guidshow: true,
  591. })
  592. return
  593. }
  594. if (step > 1) {
  595. wx.showToast({
  596. title: '请重新尝试下载',
  597. icon: 'error',
  598. duration: 2000,
  599. })
  600. return
  601. }
  602. })
  603. .finally(() => {
  604. this.setData({
  605. downloading: false,
  606. })
  607. })
  608. },
  609. hideGuid() {
  610. this.setData({
  611. guidshow: false,
  612. })
  613. },
  614. })