海南旅游项目 前端仓库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

390 lines
12 KiB

  1. <template>
  2. <view>
  3. <skeleton :loading="skeletonLoading" :row="12" :showAvatar="false" :showTitle="true">
  4. <block v-if="$isRight(goods_detail)">
  5. <!-- 商品图片轮播 -->
  6. <swiper :current="current" :indicator-dots="goods_detail.banners.length > 1 ? true : false" :circular="true" class="swiper-box" indicator-active-color="#1998FE">
  7. <swiper-item v-for="(item, index) in goods_detail.banners" :key="item.id">
  8. <image mode="aspectFill" :src="item.cover" style="width: 100%; height: 100%;" @click="lookImg(index)"></image>
  9. </swiper-item>
  10. </swiper>
  11. <!-- 商品主要信息 -->
  12. <view class="head-info">
  13. <view class="lf-font-32 lf-color-333 lf-font-bold">{{ goods_detail.name }}</view>
  14. <view class="lf-row-between lf-font-24 lf-m-t-30 lf-p-b-20">
  15. <view class="lf-flex price">
  16. <lf-price :price="goods_detail.specs[0].selling_price"></lf-price>
  17. <view class="lf-m-l-20">¥{{ goods_detail.specs[0].original_price }}</view>
  18. <view v-if="goods_detail.specs[0].cost">{{ goods_detail.specs[0].cost }}</view>
  19. </view>
  20. <view class="lf-font-24 lf-text-right">
  21. <view class="lf-color-gray">{{ goods_detail.specs[0].sold_stock_text }}</view>
  22. <!-- <view class="lf-color-primary">{{ goods_detail.specs[0].stock_text }}</view> -->
  23. </view>
  24. </view>
  25. <view class="label-box" v-if="goods_detail.tags && goods_detail.tags.length">
  26. <view class="label-item" v-for="(item, index) in goods_detail.tags" :key="index">{{ item }}</view>
  27. </view>
  28. </view>
  29. <!-- 地址信息 -->
  30. <!-- <view class="address-box">
  31. <view class="lf-font-32 lf-font-bold">适用门店</view>
  32. <view class="lf-m-t-20 lf-row-between">
  33. <view class="lf-flex">
  34. <image mode="aspectFill" class="lf-fle shop-img" :src="goods_detail.store.cover" v-if="goods_detail.store.cover"></image>
  35. <image mode="aspectFill" class="lf-fle shop-img" src="../../static/center/shop-logo.png" v-else></image>
  36. <view class="lf-font-32 lf-m-l-20 lf-line-1" style="max-width: 512rpx;">{{ goods_detail.store.name }}</view>
  37. </view>
  38. <view @click="makePhoneCall(goods_detail.store.tel)">
  39. <text class="lf-iconfont lf-icon-dianhua lf-font-40" style="color: #3A62FF;"></text>
  40. </view>
  41. </view>
  42. <view class="lf-flex lf-m-t-20" @click="openMap">
  43. <view style="width: 60rpx; height: 60rpx;" class="lf-row-center">
  44. <text class="lf-iconfont lf-icon-dizhi lf-font-40" style="color: #555555;"></text>
  45. </view>
  46. <view class="lf-m-l-20 lf-font-28" style="color: #555555;">{{ goods_detail.store.address }}</view>
  47. </view>
  48. </view> -->
  49. <!-- 商品详情 -->
  50. <view class="goods-detail">
  51. <view class="lf-font-32 lf-font-bold lf-m-b-20">旅游须知</view>
  52. <rich-text :nodes="formatRichText(goods_detail.content)" v-if="goods_detail.content_type == 'rich_text'"></rich-text>
  53. <image class="goods-img" :src="item" v-for="(item, index) in goods_detail.content" :key="index" v-if="goods_detail.content_type == 'img'"></image>
  54. </view>
  55. <!-- 修饰专用 -->
  56. <view class="extra"></view>
  57. <!-- 吸底操作按钮 -->
  58. <view class="lf-row-between fixed-bottom">
  59. <view class="lf-flex lf-p-t-10 lf-p-b-10">
  60. <view class="lf-flex-column lf-row-center icon-item" @click="$url('/pages/index/index', {type: 'switch'})">
  61. <image class="icon-img" src="../../static/center/home.png"></image>
  62. <view class="lf-m-t-1">首页</view>
  63. </view>
  64. <view class="lf-flex-column lf-row-center icon-item" @click="$url('/pages/contactService/index')">
  65. <image class="icon-img" src="../../static/center/service.png"></image>
  66. <view class="lf-m-t-1">客服</view>
  67. </view>
  68. <view class="lf-flex-column lf-row-center icon-item" @click="switchCollect">
  69. <image class="icon-img" src="../../static/center/collect-active.png" v-if="is_collect"></image>
  70. <image class="icon-img" src="../../static/center/collect.png" v-else></image>
  71. <view class="lf-m-t-1">{{ is_collect ? '已收藏' : '收藏' }}</view>
  72. </view>
  73. <button class="lf-flex-column lf-row-center icon-item" open-type="share">
  74. <image class="icon-img" src="../../static/center/share.png"></image>
  75. <view class="lf-m-t-1">分享</view>
  76. </button>
  77. </view>
  78. <button class="btn" @click="toAddOrder">立即购买</button>
  79. </view>
  80. <!-- 回到顶部 -->
  81. <!-- <u-back-top :scroll-top="pageScrollTop" :custom-style="{background: 'rgba(51, 51 51, 0.3)'}" :icon-style="{color: '#ffffff'}"></u-back-top> -->
  82. <u-back-top :scroll-top="pageScrollTop" :custom-style="{background: 'rgba(51, 51 51, 0.3)'}"></u-back-top>
  83. </block>
  84. </skeleton>
  85. </view>
  86. </template>
  87. <script>
  88. export default {
  89. data(){
  90. return {
  91. current: 0, // 轮播下标
  92. goods_id: 0,
  93. goods_detail: {},
  94. is_collect: 0, // 1为当前收藏商品了,0为否
  95. skeletonLoading: true
  96. }
  97. },
  98. onLoad(options){
  99. this.goods_id = options.id;
  100. this.getGoodsDetail();
  101. },
  102. methods: {
  103. getGoodsDetail(){
  104. let that = this;
  105. this.goods_detail = {
  106. all_specs: null,
  107. banners: [],
  108. category_id: 2,
  109. content: "<p><img src='http://sky-applet-mall.oss-cn-shenzhen.aliyuncs.com/tinymce/images/156005c5baf40ff51a327f1c34f2975b60dd6a468cdbe.jpg' alt='' width='100%' /></p>",
  110. content_type: "rich_text",
  111. cover: "http://sky-applet-mall.oss-cn-shenzhen.aliyuncs.com/images/d1c990182d6cfd6ebf1faf4077f22248.jpg!thumb_300x300_q90",
  112. created_at: "1625123492",
  113. deleted_at: null,
  114. id: 1,
  115. name: "肯德基精选午餐",
  116. share_cover: "http://sky-applet-mall.oss-cn-shenzhen.aliyuncs.com/images/d1c990182d6cfd6ebf1faf4077f22248.jpg",
  117. specs: [{
  118. cost: "",
  119. created_at: "1625470217",
  120. deleted_at: null,
  121. goods_id: 1,
  122. id: 8,
  123. limit: 10,
  124. name: "规格3",
  125. original_price: "111.00",
  126. original_price_text: "111.00",
  127. selling_price: "1.00",
  128. sold_percent: 50,
  129. sold_percent_text: "已抢50%",
  130. sold_stock: 110,
  131. sold_stock_text: "110人购买",
  132. specs: null,
  133. state: 1,
  134. stock: 110,
  135. stock_text: "库存仅剩110份",
  136. updated_at: "1625471139"
  137. }],
  138. store: {
  139. address: "广西南宁市青秀区民族大道111号",
  140. cover: "http://sky-applet-mall.oss-cn-shenzhen.aliyuncs.com/images/b4644c5226918153c0cb372e99e12bed.jpg!thumb_200x200_q90",
  141. created_at: "1625122973",
  142. deleted_at: null,
  143. id: 1,
  144. intro: null,
  145. lat: "108.3745472970581",
  146. lng: "22.813532837581967",
  147. name: "肯德基连锁餐饮",
  148. state: 2,
  149. tel: "18888888888",
  150. updated_at: "1625537146",
  151. user_id: 7
  152. },
  153. store_id: 1,
  154. tags: ["推荐"],
  155. updated_at: "1625123492",
  156. user: {is_collect: 1}
  157. }
  158. return;
  159. this.$http(this.API.API_GOODS_DETAIL, {goods_id: this.goods_id}).then(res => {
  160. this.skeletonLoading = false;
  161. this.goods_detail = res.data;
  162. this.is_collect = Boolean(res.data.user.is_collect);
  163. }).catch(err => {
  164. this.skeletonLoading = false;
  165. setTimeout(() => {
  166. that.$toBack();
  167. }, 1000);
  168. })
  169. },
  170. // 切换商品收藏
  171. switchCollect(){
  172. let userInfo = uni.getStorageSync('userinfo') || {};
  173. if(!userInfo.id || !userInfo.nickname || !userInfo.avatar){
  174. this.$url('/pages/login/index?type=userinfo');
  175. return;
  176. }
  177. this.$http(this.API.API_COLLECT_DEAL, {goods_id: this.goods_id}).then(res => {
  178. this.$msg(res.msg);
  179. this.is_collect = Boolean(res.data.user.is_collect);
  180. })
  181. },
  182. // 拨打电话
  183. makePhoneCall(phoneStr){
  184. uni.makePhoneCall({
  185. phoneNumber: String(phoneStr)
  186. })
  187. },
  188. // 打开地图
  189. openMap(){
  190. let { address, lat, lng } = this.goods_detail?.store || {};
  191. uni.openLocation({
  192. longitude: Number(lat),
  193. latitude: Number(lng),
  194. scale: 20,
  195. name: address
  196. });
  197. },
  198. // 跳转到确认下单页面
  199. toAddOrder(){
  200. let goods_id = this.goods_detail.id;
  201. let goods_specs_id = this.goods_detail.specs[0].id
  202. this.$url('/pages/order/confirm-order?goods_id='+ goods_id +'&goods_specs_id='+ goods_specs_id);
  203. },
  204. // 预览图片
  205. lookImg(index){
  206. this.$u.throttle(() => {
  207. let goods_banner = this.goods_detail.banners || [];
  208. let banners = goods_banner.map(item => item.cover);
  209. uni.previewImage({
  210. urls: banners,
  211. current: index
  212. })
  213. }, 200);
  214. },
  215. // 富文本处理
  216. formatRichText(richText){
  217. if(richText != null){
  218. let newRichText= richText.replace(/<img[^>]*>/gi, function(match, capture){
  219. match = match.replace(/style="[^"]+"/gi, '').replace(/style='[^']+'/gi, '');
  220. match = match.replace(/width="[^"]+"/gi, '').replace(/width='[^']+'/gi, '');
  221. match = match.replace(/height="[^"]+"/gi, '').replace(/height='[^']+'/gi, '');
  222. return match;
  223. });
  224. newRichText = newRichText.replace(/style="[^"]+"/gi,function(match, capture){
  225. match = match.replace(/width:[^;]+;/gi, 'width:100%;').replace(/width:[^;]+;/gi, 'width:100%;');
  226. return match;
  227. });
  228. newRichText = newRichText.replace(/<br[^>]*\/>/gi, '');
  229. newRichText = newRichText.replace(/\<img/gi, '<img style="width:100%;height:auto;display:block;margin:10px 0;"');
  230. return newRichText;
  231. }else{
  232. return null;
  233. }
  234. }
  235. },
  236. onShareAppMessage(){
  237. let goods = this.goods_detail;
  238. let title = goods.name;
  239. let imageUrl = goods.share_cover || goods.cover;
  240. let path = '/pages/route/index?route=goods_detail&id='+ goods.id;
  241. return {
  242. title,
  243. path,
  244. imageUrl
  245. }
  246. }
  247. }
  248. </script>
  249. <style>
  250. page{
  251. background-color: #f5f5f5;
  252. overflow-x: hidden;
  253. }
  254. </style>
  255. <style lang="scss" scoped="scoped">
  256. .swiper-box{
  257. width: 750rpx;
  258. height: 490rpx;
  259. background-color: #FFFFFF;
  260. }
  261. .head-info{
  262. width: 750rpx;
  263. height: auto;
  264. box-sizing: border-box;
  265. padding: 0 32rpx;
  266. padding-top: 20rpx;
  267. background-color: #FFFFFF;
  268. // .price>view:nth-of-type(1){
  269. // color: #FF0000;
  270. // margin-right: 22rpx;
  271. // font-weight: bold;
  272. // }
  273. .price>view:nth-of-type(1){
  274. text-decoration: line-through;
  275. color: #777777;
  276. margin-right: 22rpx;
  277. }
  278. .price>view:nth-of-type(2){
  279. width: max-content;
  280. padding: 0 18rpx;
  281. height: 46rpx;
  282. background-color: #1998FE;
  283. border-radius: 10rpx;
  284. display: flex;
  285. justify-content: center;
  286. align-items: center;
  287. color: #FFFFFF;
  288. }
  289. .label-box{
  290. min-height: 130rpx;
  291. width: 100%;
  292. border-top: 1rpx solid #E5E5E5;
  293. display: flex;
  294. flex-wrap: wrap;
  295. padding: 30rpx 0 10rpx 0;
  296. .label-item{
  297. width: 156rpx;
  298. height: 70rpx;
  299. border-radius: 10rpx;
  300. border: 2rpx solid #1998FE;
  301. display: flex;
  302. justify-content: center;
  303. align-items: center;
  304. font-size: 28rpx;
  305. color: #1998FE;
  306. margin-right: 20rpx;
  307. margin-bottom: 20rpx;
  308. }
  309. }
  310. }
  311. .address-box{
  312. width: 750rpx;
  313. height: auto;
  314. box-sizing: border-box;
  315. background-color: #FFFFFF;
  316. padding: 32rpx;
  317. margin-top: 20rpx;
  318. .shop-img{
  319. width: 60rpx;
  320. height: 60rpx;
  321. border-radius: 50%;
  322. }
  323. }
  324. .goods-detail{
  325. width: 750rpx;
  326. height: auto;
  327. background-color: #FFFFFF;
  328. padding: 32rpx;
  329. box-sizing: border-box;
  330. margin-top: 20rpx;
  331. .goods-img{
  332. width: 100%;
  333. }
  334. }
  335. .extra{
  336. width: 100%;
  337. height: 120rpx;
  338. padding-bottom: constant(safe-area-inset-bottom);
  339. padding-bottom: env(safe-area-inset-bottom);
  340. box-sizing: content-box;
  341. }
  342. .fixed-bottom{
  343. position: fixed;
  344. bottom: 0;
  345. left: 0;
  346. background-color: #FFFFFF;
  347. width: 100%;
  348. height: auto;
  349. padding: 0 32rpx;
  350. border-top: 1rpx solid #e5e5e5;
  351. padding-bottom: constant(safe-area-inset-bottom);
  352. padding-bottom: env(safe-area-inset-bottom);
  353. .icon-item{
  354. margin-right: 16rpx;
  355. background-color: transparent;
  356. margin: 0;
  357. line-height: initial;
  358. font-size: 28rpx;
  359. font-weight: inherit;
  360. margin-right: 10rpx;
  361. padding: 0;
  362. width: 88rpx;
  363. &:first-child{
  364. padding-left: 0;
  365. }
  366. .icon-img{
  367. height: 50rpx;
  368. width: 50rpx;
  369. }
  370. }
  371. .btn{
  372. margin: 0;
  373. padding: 0;
  374. width: 208rpx;
  375. height: 80rpx;
  376. background-color: #1998FE;
  377. color: #FFFFFF;
  378. line-height: 80rpx;
  379. font-size: 32rpx;
  380. border-radius: 42rpx;
  381. }
  382. }
  383. </style>