index.ts 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688
  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. if (!isLogin()) {
  139. wx.showToast({
  140. title: '为提供更好的服务,请登录',
  141. duration: 1000,
  142. success() {
  143. setTimeout(() => {
  144. Navi.navigateTo({
  145. url: '/pages/login/index',
  146. })
  147. }, 10)
  148. },
  149. })
  150. return
  151. }
  152. const id = this.data.id
  153. const cateid = this.data.cateid
  154. GoodApi.GetProduct({ id, cateid } as any).then((rsp) => {
  155. if (rsp.result) {
  156. const details = rsp.result
  157. const {
  158. imageUrl: primaryImage,
  159. soldNum,
  160. limitMaxCount,
  161. limitMinCount,
  162. limitBuyInfo,
  163. unit,
  164. } = details
  165. const skuArray = [] as {
  166. skuId: number
  167. quantity: number
  168. image: string
  169. price: number
  170. linePrice: number
  171. specInfo: TmpSpecInfo[]
  172. }[]
  173. if (details.skuList) {
  174. details.skuList.forEach((item) => {
  175. const priceInfo = item.priceInfo || []
  176. const len = priceInfo.length
  177. skuArray.push({
  178. skuId: Number(item.skuId),
  179. image: item.skuImage || primaryImage || '',
  180. price: len > 0 ? priceInfo[0].price : 0,
  181. linePrice: len > 1 ? priceInfo[1].price : 0,
  182. quantity: item.stockInfo ? item.stockInfo.stockQuantity : 0,
  183. specInfo: item.specInfo || [],
  184. })
  185. })
  186. }
  187. let pics = []
  188. if (rsp.result.imageUrl) {
  189. pics.push(rsp.result.imageUrl)
  190. }
  191. if (rsp.result.images && rsp.result.images.length > 0) {
  192. pics = pics.concat(rsp.result.images)
  193. }
  194. const hasDraw =
  195. (details.draws && details.draws.length > 0) ||
  196. (details.draws2D && details.draws2D.length > 0)
  197. this.setData({
  198. details,
  199. nodraws: !hasDraw,
  200. swipepics: pics,
  201. current: 0,
  202. loading: false,
  203. primaryImage,
  204. isStock: details.spuStockQuantity > 0,
  205. maxSalePrice: details.maxSalePrice,
  206. maxLinePrice: details.maxLinePrice,
  207. minSalePrice: details.minSalePrice,
  208. minLinePrice: details.minLinePrice,
  209. skuArray: skuArray as any,
  210. soldout: details.isPutOnSale === 0,
  211. soldNum,
  212. limitMaxCount,
  213. limitMinCount,
  214. limitBuyInfo,
  215. unit,
  216. })
  217. this.setFav(rsp.result.isFav)
  218. wx.setNavigationBarTitle({
  219. title: rsp.result.title || '',
  220. })
  221. console.log(rsp.result)
  222. }
  223. })
  224. // GoodApi.GetFav({ id, cateId: cateid }).then((rsp) => {
  225. // if (rsp.result && rsp.result.length > 0) {
  226. // this.setData({
  227. // favList: rsp.result,
  228. // })
  229. // }
  230. // })
  231. GoodApi.GetComments({ id }).then((rsp) => {
  232. if (rsp.result) {
  233. this.setData({
  234. commentsDto: rsp.result,
  235. })
  236. }
  237. })
  238. this.loadRecommend(true)
  239. },
  240. loadRecommend(rest = false) {
  241. console.log('next')
  242. this.setData({
  243. loadMoreStatus: 1,
  244. })
  245. GoodApi.GetHomeRecommend(this.data.albumInput as any).then((rsp) => {
  246. if (rsp.result) {
  247. const result = rsp.result as any
  248. const { items = [] } = result
  249. const nowItems = rest ? items : this.data.favList.concat(items)
  250. this.setData({
  251. favList: nowItems as any,
  252. favTotal: result.totalCount || 0,
  253. loadMoreStatus: nowItems.length === result.totalCount ? 2 : 0,
  254. })
  255. }
  256. })
  257. },
  258. handleReachBottom() {
  259. if (this.data.loadMoreStatus === 0 && this.data.favList.length < this.data.favTotal) {
  260. this.setData(
  261. {
  262. albumInput: {
  263. ...this.data.albumInput,
  264. skipCount: this.data.albumInput.skipCount + 10,
  265. },
  266. },
  267. () => {
  268. this.loadRecommend()
  269. },
  270. )
  271. }
  272. },
  273. /**
  274. * 生命周期函数--监听页面加载
  275. */
  276. onLoad(query: Record<string, string>) {
  277. const { id, cateid } = query
  278. this.setData({
  279. id: Number(id),
  280. cateid: Number(cateid),
  281. })
  282. },
  283. /**
  284. * 生命周期函数--监听页面初次渲染完成
  285. */
  286. onReady() {},
  287. /**
  288. * 生命周期函数--监听页面显示
  289. */
  290. onShow() {},
  291. /**
  292. * 生命周期函数--监听页面隐藏
  293. */
  294. onHide() {},
  295. /**
  296. * 生命周期函数--监听页面卸载
  297. */
  298. onUnload() {},
  299. /**
  300. * 页面相关事件处理函数--监听用户下拉动作
  301. */
  302. onPullDownRefresh() {},
  303. /**
  304. * 页面上拉触底事件的处理函数
  305. */
  306. onReachBottom() {},
  307. /**
  308. * 用户点击右上角分享
  309. */
  310. onShareAppMessage(e: WechatMiniprogram.Page.IShareAppMessageOption) {
  311. console.log(e, 'ssss')
  312. // const promise = new Promise((resolve) => {
  313. // setTimeout(() => {
  314. // resolve({
  315. // title: '自定义转发标题',
  316. // })
  317. // }, 2000)
  318. // })
  319. const url = getCurrentUrl()
  320. return {
  321. title: this.data.details.title,
  322. path: url,
  323. imageUrl: this.data.swipepics[0],
  324. //promise,
  325. }
  326. },
  327. onPreview(e: WechatMiniprogram.BaseEvent<{ idx: number }>) {
  328. const { idx = 0 } = e.currentTarget.dataset
  329. wx.previewImage({
  330. urls: this.data.swipepics,
  331. current: this.data.swipepics[idx],
  332. })
  333. },
  334. gotoGoodsDetail(e: WechatMiniprogram.CustomEvent<{ goods: WxCateAlbumItemDto; index: number }>) {
  335. const { goods } = e.detail
  336. Navi.redirectTo({
  337. url: '/pages/goods/detail/index?id=' + goods.id + '&cateid=' + this.data.cateid,
  338. })
  339. },
  340. /**
  341. *
  342. */
  343. chooseSpecItem(
  344. e: WechatMiniprogram.CustomEvent<{
  345. selectedSku: Record<string, string>
  346. isAllSelectedSku: boolean
  347. }>,
  348. ) {
  349. const { specList } = this.data.details
  350. const { selectedSku, isAllSelectedSku } = e.detail
  351. console.log(specList, isAllSelectedSku, selectedSku)
  352. if (!isAllSelectedSku) {
  353. this.setData({
  354. selectSkuSellPrice: 0,
  355. })
  356. }
  357. this.setData({
  358. isAllSelectedSku,
  359. })
  360. this.getSkuItem(specList, selectedSku)
  361. },
  362. getSkuItem(specList: TmpSpec[] | undefined, selectedSku: Record<string, string>) {
  363. const { skuArray, primaryImage, unit } = this.data
  364. const selectedSkuValues = this.getSelectedSkuValues(specList, selectedSku)
  365. let selectedAttrStr = ` ${unit} `
  366. selectedSkuValues.forEach((item) => {
  367. selectedAttrStr += `,${item.specValue} `
  368. })
  369. // eslint-disable-next-line array-callback-return
  370. const findSkuItem = skuArray.filter((item) => {
  371. let status = true
  372. ;(item.specInfo || []).forEach((subItem) => {
  373. if (!selectedSku[subItem.specId] || selectedSku[subItem.specId] !== subItem.specValueId) {
  374. status = false
  375. }
  376. })
  377. if (status) return item
  378. })
  379. this.selectSpecsName(selectedSkuValues.length > 0 ? selectedAttrStr : '')
  380. console.log('find sku:', findSkuItem)
  381. if (findSkuItem && findSkuItem.length > 0) {
  382. const selectItem = findSkuItem[0]
  383. this.setData({
  384. specImg: selectItem.image,
  385. selectItem,
  386. selectSkuSellPrice: selectItem.price || 0,
  387. selectSkuLinePrice: selectItem.linePrice || 0,
  388. })
  389. } else {
  390. this.setData({
  391. specImg: primaryImage,
  392. selectItem: null,
  393. selectSkuSellPrice: 0,
  394. selectSkuLinePrice: 0,
  395. })
  396. }
  397. },
  398. getSelectedSkuValues(skuTree, selectedSku) {
  399. const normalizedTree = this.normalizeSkuTree(skuTree)
  400. return Object.keys(selectedSku).reduce((selectedValues, skuKeyStr) => {
  401. const skuValues = normalizedTree[skuKeyStr]
  402. const skuValueId = selectedSku[skuKeyStr]
  403. if (skuValueId !== '') {
  404. const skuValue = skuValues.filter((value) => {
  405. return value.specValueId === skuValueId
  406. })[0]
  407. skuValue && selectedValues.push(skuValue)
  408. }
  409. return selectedValues
  410. }, [])
  411. },
  412. normalizeSkuTree(skuTree) {
  413. const normalizedTree = {}
  414. skuTree.forEach((treeItem) => {
  415. normalizedTree[treeItem.specId] = treeItem.specValueList
  416. })
  417. return normalizedTree
  418. },
  419. selectSpecsName(selectSpecsName: string) {
  420. if (selectSpecsName) {
  421. this.setData({
  422. selectedAttrStr: selectSpecsName,
  423. })
  424. } else {
  425. this.setData({
  426. selectedAttrStr: '',
  427. })
  428. }
  429. },
  430. /**
  431. * SPU 选择器
  432. */
  433. handlePopupHide() {
  434. this.setData({
  435. isSpuSelectPopupShow: false,
  436. })
  437. },
  438. showSkuSelectPopup(type: number) {
  439. console.log(type)
  440. this.setData({
  441. buyType: type || 0,
  442. outOperateStatus: type >= 1,
  443. isSpuSelectPopupShow: true,
  444. })
  445. },
  446. toAddCart() {
  447. this.showSkuSelectPopup(2)
  448. },
  449. specsConfirm(e: WechatMiniprogram.CustomEvent<{ buy: number }>) {
  450. const { buy } = e.detail
  451. this.setData(
  452. {
  453. buyNum: buy,
  454. },
  455. () => {
  456. this.addCart()
  457. this.handlePopupHide()
  458. },
  459. )
  460. },
  461. setFav(state: boolean) {
  462. const arr = JSON.parse(JSON.stringify(this.data.jumpArray))
  463. arr[1].fav = state
  464. arr[1].selected = state
  465. this.setData({
  466. jumpArray: arr,
  467. })
  468. },
  469. toNav(e: WechatMiniprogram.CustomEvent<{ index: number; url: string }>) {
  470. const { index } = e.detail
  471. const node = this.data.jumpArray[index]
  472. const url = node.url
  473. if (url && url.length > 0) {
  474. if (node.switchTab) {
  475. wx.switchTab({
  476. url,
  477. })
  478. } else {
  479. wx.navigateTo({
  480. url,
  481. })
  482. }
  483. return
  484. }
  485. if (node.title === '收藏') {
  486. const state = node.fav === true ? false : true
  487. GoodApi.UpdateFav({ id: this.data.id, state }).then((rsp) => {
  488. this.setFav(state)
  489. })
  490. }
  491. console.log(node)
  492. },
  493. addCart() {
  494. const { isAllSelectedSku, selectItem, buyNum } = this.data
  495. // skuId: 154
  496. // specInfo: Array(2)
  497. // 0: {specId: 58, specTitle: null, specValueId: 170, specValue: "AL002黑色(铝合金框)", image: null}
  498. // 1: {specId: 59, specTitle: null, specValueId: 175, specValue: "80*120cm", image: null}
  499. if (selectItem) {
  500. const bag: WxAddCartInput = {
  501. cateId: this.data.cateid,
  502. goodId: this.data.id,
  503. skuId: selectItem.skuId,
  504. info: selectItem.specInfo.map((o: any) => o.specValueId),
  505. buyNum,
  506. } as any
  507. this.setData({
  508. addingCart: true,
  509. })
  510. GoodApi.AddCart(bag)
  511. .then((rsp) => {
  512. if (rsp.result === 'ok') {
  513. Toast({
  514. context: this,
  515. selector: '#t-toast',
  516. message: '已添加购物车',
  517. icon: '',
  518. duration: 1000,
  519. })
  520. }
  521. })
  522. .catch((e) => {
  523. console.log(e)
  524. Toast({
  525. context: this,
  526. selector: '#t-toast',
  527. message: '添加购物车不成功',
  528. icon: '',
  529. duration: 1000,
  530. })
  531. })
  532. .finally(() => {
  533. this.setData({
  534. addingCart: false,
  535. })
  536. })
  537. }
  538. },
  539. gotoDraw() {
  540. console.log('hihihi')
  541. this.setData({
  542. drawshow: true,
  543. })
  544. },
  545. gotoFly(e: WechatMiniprogram.BaseEvent<{}, { type: string }>) {
  546. const type = e.currentTarget.dataset.type
  547. let can = false
  548. let id = -1
  549. if (type === 'flat' && this.data.details.draws2D && this.data.details.draws2D.length > 0) {
  550. can = true
  551. id = this.data.details.draws2D[0].id
  552. } else if (type === 'space' && this.data.details.draws && this.data.details.draws.length > 0) {
  553. can = true
  554. id = this.data.details.draws[0].id
  555. }
  556. if (can) {
  557. GoodApi.GetDrawLink({
  558. id: id,
  559. goodId: this.data.id,
  560. type,
  561. }).then((rsp) => {
  562. if (rsp.result && rsp.result.length > 0) {
  563. console.log('navi')
  564. Navi.navigateTo({
  565. url: '/pages/outlink/index?url=' + encodeURIComponent(rsp.result),
  566. })
  567. }
  568. })
  569. }
  570. },
  571. handleDrawPopupHide() {
  572. this.setData({
  573. drawshow: false,
  574. })
  575. },
  576. gotoComments() {
  577. let urlQueryStr = obj2Params({
  578. spuId: this.data.id,
  579. gid: this.data.gid,
  580. } as any)
  581. urlQueryStr = urlQueryStr ? `?${urlQueryStr}` : ''
  582. const path = `/pages/goods/comments/index${urlQueryStr}`
  583. wx.navigateTo({
  584. url: path,
  585. })
  586. },
  587. onSwipeChange(e: WechatMiniprogram.CustomEvent<{ current: number }>) {
  588. const { current } = e.detail
  589. this.setData({
  590. current,
  591. })
  592. },
  593. gotoshare() {},
  594. gotodownload() {
  595. this.setData({
  596. downloading: true,
  597. })
  598. saveToAlbum(this.data.swipepics[0])
  599. .then((step: Number) => {
  600. if (step === 1) {
  601. this.setData({
  602. guidshow: true,
  603. })
  604. return
  605. }
  606. if (step > 1) {
  607. wx.showToast({
  608. title: '请重新尝试下载',
  609. icon: 'error',
  610. duration: 2000,
  611. })
  612. return
  613. }
  614. })
  615. .finally(() => {
  616. this.setData({
  617. downloading: false,
  618. })
  619. })
  620. },
  621. hideGuid() {
  622. this.setData({
  623. guidshow: false,
  624. })
  625. },
  626. })