index.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. import Toast from 'tdesign-miniprogram/toast/index';
  2. import { fetchGood } from '../../../services/good/fetchGood';
  3. import { fetchActivityList } from '../../../services/activity/fetchActivityList';
  4. import {
  5. getGoodsDetailsCommentList,
  6. getGoodsDetailsCommentsCount,
  7. } from '../../../services/good/fetchGoodsDetailsComments';
  8. import { cdnBase } from '../../../config/index';
  9. const imgPrefix = `${cdnBase}/`;
  10. const recLeftImg = `${imgPrefix}common/rec-left.png`;
  11. const recRightImg = `${imgPrefix}common/rec-right.png`;
  12. const obj2Params = (obj = {}, encode = false) => {
  13. const result = [];
  14. Object.keys(obj).forEach((key) => result.push(`${key}=${encode ? encodeURIComponent(obj[key]) : obj[key]}`));
  15. return result.join('&');
  16. };
  17. Page({
  18. data: {
  19. commentsList: [],
  20. commentsStatistics: {
  21. badCount: 0,
  22. commentCount: 0,
  23. goodCount: 0,
  24. goodRate: 0,
  25. hasImageCount: 0,
  26. middleCount: 0,
  27. },
  28. isShowPromotionPop: false,
  29. activityList: [],
  30. recLeftImg,
  31. recRightImg,
  32. details: {},
  33. goodsTabArray: [
  34. {
  35. name: '商品',
  36. value: '', // 空字符串代表置顶
  37. },
  38. {
  39. name: '详情',
  40. value: 'goods-page',
  41. },
  42. ],
  43. storeLogo: `${imgPrefix}common/store-logo.png`,
  44. storeName: '云mall标准版旗舰店',
  45. jumpArray: [
  46. {
  47. title: '首页',
  48. url: '/pages/home/home',
  49. iconName: 'home',
  50. },
  51. {
  52. title: '购物车',
  53. url: '/pages/cart/index',
  54. iconName: 'cart',
  55. showCartNum: true,
  56. },
  57. ],
  58. isStock: true,
  59. cartNum: 0,
  60. soldout: false,
  61. buttonType: 1,
  62. buyNum: 1,
  63. selectedAttrStr: '',
  64. skuArray: [],
  65. primaryImage: '',
  66. specImg: '',
  67. isSpuSelectPopupShow: false,
  68. isAllSelectedSku: false,
  69. buyType: 0,
  70. outOperateStatus: false, // 是否外层加入购物车
  71. operateType: 0,
  72. selectSkuSellsPrice: 0,
  73. maxLinePrice: 0,
  74. minSalePrice: 0,
  75. maxSalePrice: 0,
  76. list: [],
  77. spuId: '',
  78. navigation: { type: 'fraction' },
  79. current: 0,
  80. autoplay: true,
  81. duration: 500,
  82. interval: 5000,
  83. soldNum: 0, // 已售数量
  84. },
  85. handlePopupHide() {
  86. this.setData({
  87. isSpuSelectPopupShow: false,
  88. });
  89. },
  90. showSkuSelectPopup(type) {
  91. this.setData({
  92. buyType: type || 0,
  93. outOperateStatus: type >= 1,
  94. isSpuSelectPopupShow: true,
  95. });
  96. },
  97. buyItNow() {
  98. this.showSkuSelectPopup(1);
  99. },
  100. toAddCart() {
  101. this.showSkuSelectPopup(2);
  102. },
  103. toNav(e) {
  104. const { url } = e.detail;
  105. wx.switchTab({
  106. url: url,
  107. });
  108. },
  109. showCurImg(e) {
  110. const { index } = e.detail;
  111. const { images } = this.data.details;
  112. wx.previewImage({
  113. current: images[index],
  114. urls: images, // 需要预览的图片http链接列表
  115. });
  116. },
  117. onPageScroll({ scrollTop }) {
  118. const goodsTab = this.selectComponent('#goodsTab');
  119. goodsTab && goodsTab.onScroll(scrollTop);
  120. },
  121. chooseSpecItem(e) {
  122. const { specList } = this.data.details;
  123. const { selectedSku, isAllSelectedSku } = e.detail;
  124. if (!isAllSelectedSku) {
  125. this.setData({
  126. selectSkuSellsPrice: 0,
  127. });
  128. }
  129. this.setData({
  130. isAllSelectedSku,
  131. });
  132. this.getSkuItem(specList, selectedSku);
  133. },
  134. getSkuItem(specList, selectedSku) {
  135. const { skuArray, primaryImage } = this.data;
  136. const selectedSkuValues = this.getSelectedSkuValues(specList, selectedSku);
  137. let selectedAttrStr = ` 件 `;
  138. selectedSkuValues.forEach((item) => {
  139. selectedAttrStr += `,${item.specValue} `;
  140. });
  141. // eslint-disable-next-line array-callback-return
  142. const skuItem = skuArray.filter((item) => {
  143. let status = true;
  144. (item.specInfo || []).forEach((subItem) => {
  145. if (!selectedSku[subItem.specId] || selectedSku[subItem.specId] !== subItem.specValueId) {
  146. status = false;
  147. }
  148. });
  149. if (status) return item;
  150. });
  151. this.selectSpecsName(selectedSkuValues.length > 0 ? selectedAttrStr : '');
  152. if (skuItem) {
  153. this.setData({
  154. selectItem: skuItem,
  155. selectSkuSellsPrice: skuItem.price || 0,
  156. });
  157. } else {
  158. this.setData({
  159. selectItem: null,
  160. selectSkuSellsPrice: 0,
  161. });
  162. }
  163. this.setData({
  164. specImg: skuItem && skuItem.skuImage ? skuItem.skuImage : primaryImage,
  165. });
  166. },
  167. // 获取已选择的sku名称
  168. getSelectedSkuValues(skuTree, selectedSku) {
  169. const normalizedTree = this.normalizeSkuTree(skuTree);
  170. return Object.keys(selectedSku).reduce((selectedValues, skuKeyStr) => {
  171. const skuValues = normalizedTree[skuKeyStr];
  172. const skuValueId = selectedSku[skuKeyStr];
  173. if (skuValueId !== '') {
  174. const skuValue = skuValues.filter((value) => {
  175. return value.specValueId === skuValueId;
  176. })[0];
  177. skuValue && selectedValues.push(skuValue);
  178. }
  179. return selectedValues;
  180. }, []);
  181. },
  182. normalizeSkuTree(skuTree) {
  183. const normalizedTree = {};
  184. skuTree.forEach((treeItem) => {
  185. normalizedTree[treeItem.specId] = treeItem.specValueList;
  186. });
  187. return normalizedTree;
  188. },
  189. selectSpecsName(selectSpecsName) {
  190. if (selectSpecsName) {
  191. this.setData({
  192. selectedAttrStr: selectSpecsName,
  193. });
  194. } else {
  195. this.setData({
  196. selectedAttrStr: '',
  197. });
  198. }
  199. },
  200. addCart() {
  201. const { isAllSelectedSku } = this.data;
  202. Toast({
  203. context: this,
  204. selector: '#t-toast',
  205. message: isAllSelectedSku ? '点击加入购物车' : '请选择规格',
  206. icon: '',
  207. duration: 1000,
  208. });
  209. },
  210. gotoBuy(type) {
  211. const { isAllSelectedSku, buyNum } = this.data;
  212. if (!isAllSelectedSku) {
  213. Toast({
  214. context: this,
  215. selector: '#t-toast',
  216. message: '请选择规格',
  217. icon: '',
  218. duration: 1000,
  219. });
  220. return;
  221. }
  222. this.handlePopupHide();
  223. const query = {
  224. quantity: buyNum,
  225. storeId: '1',
  226. spuId: this.data.spuId,
  227. goodsName: this.data.details.title,
  228. skuId: type === 1 ? this.data.skuList[0].skuId : this.data.selectItem.skuId,
  229. available: this.data.details.available,
  230. price: this.data.details.minSalePrice,
  231. specInfo: this.data.details.specList?.map((item) => ({
  232. specTitle: item.title,
  233. specValue: item.specValueList[0].specValue,
  234. })),
  235. primaryImage: this.data.details.primaryImage,
  236. spuId: this.data.details.spuId,
  237. thumb: this.data.details.primaryImage,
  238. title: this.data.details.title,
  239. };
  240. let urlQueryStr = obj2Params({
  241. goodsRequestList: JSON.stringify([query]),
  242. });
  243. urlQueryStr = urlQueryStr ? `?${urlQueryStr}` : '';
  244. const path = `/pages/order/order-confirm/index${urlQueryStr}`;
  245. wx.navigateTo({
  246. url: path,
  247. });
  248. },
  249. specsConfirm() {
  250. const { buyType } = this.data;
  251. if (buyType === 1) {
  252. this.gotoBuy();
  253. } else {
  254. this.addCart();
  255. }
  256. // this.handlePopupHide();
  257. },
  258. changeNum(e) {
  259. this.setData({
  260. buyNum: e.detail.buyNum,
  261. });
  262. },
  263. closePromotionPopup() {
  264. this.setData({
  265. isShowPromotionPop: false,
  266. });
  267. },
  268. promotionChange(e) {
  269. const { index } = e.detail;
  270. wx.navigateTo({
  271. url: `/pages/promotion/promotion-detail/index?promotion_id=${index}`,
  272. });
  273. },
  274. showPromotionPopup() {
  275. this.setData({
  276. isShowPromotionPop: true,
  277. });
  278. },
  279. getDetail(spuId) {
  280. Promise.all([fetchGood(spuId), fetchActivityList()]).then((res) => {
  281. const [details, activityList] = res;
  282. const skuArray = [];
  283. const { skuList, primaryImage, isPutOnSale, minSalePrice, maxSalePrice, maxLinePrice, soldNum } = details;
  284. skuList.forEach((item) => {
  285. skuArray.push({
  286. skuId: item.skuId,
  287. quantity: item.stockInfo ? item.stockInfo.stockQuantity : 0,
  288. specInfo: item.specInfo,
  289. });
  290. });
  291. const promotionArray = [];
  292. activityList.forEach((item) => {
  293. promotionArray.push({
  294. tag: item.promotionSubCode === 'MYJ' ? '满减' : '满折',
  295. label: '满100元减99.9元',
  296. });
  297. });
  298. this.setData({
  299. details,
  300. activityList,
  301. isStock: details.spuStockQuantity > 0,
  302. maxSalePrice: maxSalePrice ? parseInt(maxSalePrice) : 0,
  303. maxLinePrice: maxLinePrice ? parseInt(maxLinePrice) : 0,
  304. minSalePrice: minSalePrice ? parseInt(minSalePrice) : 0,
  305. list: promotionArray,
  306. skuArray: skuArray,
  307. primaryImage,
  308. soldout: isPutOnSale === 0,
  309. soldNum,
  310. });
  311. });
  312. },
  313. async getCommentsList() {
  314. try {
  315. const code = 'Success';
  316. const data = await getGoodsDetailsCommentList();
  317. const { homePageComments } = data;
  318. if (code.toUpperCase() === 'SUCCESS') {
  319. const nextState = {
  320. commentsList: homePageComments.map((item) => {
  321. return {
  322. goodsSpu: item.spuId,
  323. userName: item.userName || '',
  324. commentScore: item.commentScore,
  325. commentContent: item.commentContent || '用户未填写评价',
  326. userHeadUrl: item.isAnonymity ? this.anonymityAvatar : item.userHeadUrl || this.anonymityAvatar,
  327. };
  328. }),
  329. };
  330. this.setData(nextState);
  331. }
  332. } catch (error) {
  333. console.error('comments error:', error);
  334. }
  335. },
  336. onShareAppMessage() {
  337. // 自定义的返回信息
  338. const { selectedAttrStr } = this.data;
  339. let shareSubTitle = '';
  340. if (selectedAttrStr.indexOf('件') > -1) {
  341. const count = selectedAttrStr.indexOf('件');
  342. shareSubTitle = selectedAttrStr.slice(count + 1, selectedAttrStr.length);
  343. }
  344. const customInfo = {
  345. imageUrl: this.data.details.primaryImage,
  346. title: this.data.details.title + shareSubTitle,
  347. path: `/pages/goods/details/index?spuId=${this.data.spuId}`,
  348. };
  349. return customInfo;
  350. },
  351. /** 获取评价统计 */
  352. async getCommentsStatistics() {
  353. try {
  354. const code = 'Success';
  355. const data = await getGoodsDetailsCommentsCount();
  356. if (code.toUpperCase() === 'SUCCESS') {
  357. const { badCount, commentCount, goodCount, goodRate, hasImageCount, middleCount } = data;
  358. const nextState = {
  359. commentsStatistics: {
  360. badCount: parseInt(`${badCount}`),
  361. commentCount: parseInt(`${commentCount}`),
  362. goodCount: parseInt(`${goodCount}`),
  363. /** 后端返回百分比后数据但没有限制位数 */
  364. goodRate: Math.floor(goodRate * 10) / 10,
  365. hasImageCount: parseInt(`${hasImageCount}`),
  366. middleCount: parseInt(`${middleCount}`),
  367. },
  368. };
  369. this.setData(nextState);
  370. }
  371. } catch (error) {
  372. console.error('comments statiistics error:', error);
  373. }
  374. },
  375. /** 跳转到评价列表 */
  376. navToCommentsListPage() {
  377. wx.navigateTo({
  378. url: `/pages/goods/comments/index?spuId=${this.data.spuId}`,
  379. });
  380. },
  381. onLoad(query) {
  382. const { spuId } = query;
  383. this.setData({
  384. spuId: spuId,
  385. });
  386. this.getDetail(spuId);
  387. this.getCommentsList(spuId);
  388. this.getCommentsStatistics(spuId);
  389. },
  390. });