shopIndex.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  1. <template>
  2. <div class="shop-index">
  3. <div class="shop-head">
  4. <div class="shop-logo">
  5. <div class="img">
  6. <img :src="this.shopInfo.shopLogo" alt />
  7. </div>
  8. <div class="text">
  9. <div class="name">{{ this.shopInfo.shopName }}</div>
  10. <div class="operation">
  11. <div class="self" v-if="this.shopInfo.shopId == 1">
  12. {{ $t('shopInfo.selfShop') }}
  13. </div>
  14. <div class="self" v-else>
  15. {{ this.shopInfo.type == 1 ? $t('shopInfo.preferredStores') : $t('shopInfo.generalStore') }}
  16. </div>
  17. <div
  18. class="favourite"
  19. :class="{ active: this.isCollection }"
  20. @click="shopCollection()"
  21. >
  22. <i class="icon"></i>
  23. {{ this.isCollection ? $t('shopInfo.followed') : $t('shopInfo.follow') }}
  24. </div>
  25. </div>
  26. </div>
  27. </div>
  28. <div class="shop-news">
  29. <div class="news-tit">
  30. <div class="tit">{{$t('storeAnnouncement')}}</div>
  31. <div class="more" @click="toNewsList" v-if="noticeList.length">
  32. {{$t('more')}}&nbsp;&nbsp;
  33. </div>
  34. </div>
  35. <div class="news-list-con" v-if="noticeList.length">
  36. <div
  37. class="news-item"
  38. v-for="(news, index) in noticeList"
  39. :key="index"
  40. @click="toNewsDet(news.id)"
  41. >
  42. {{ news.title }}
  43. </div>
  44. </div>
  45. <div class="news-empty" v-else>
  46. {{$t('shopInfo.noAnnouncement')}}
  47. </div>
  48. </div>
  49. </div>
  50. <div class="shop-menu">
  51. <div class="menu-box">
  52. <div class="menu-list">
  53. <div class="menu">
  54. <a href="javascript:void(0);" @click="homePage" class="menu-link"
  55. >{{$t('shopInfo.homePage')}}</a
  56. >
  57. </div>
  58. <div class="menu all-category">
  59. <a
  60. href="javascript:void(0);"
  61. class="menu-link"
  62. @click="getProdListByCategory()"
  63. >{{$t('shopInfo.allCategories')}}</a
  64. >
  65. <div class="menu-wrap">
  66. <div
  67. class="wrap-item"
  68. v-for="category in this.categoryList"
  69. :key="category.categoryId"
  70. v-show='category.categoryId'
  71. >
  72. <div class="item-tit">
  73. <a
  74. href="javascript:void(0);"
  75. @click="getProdListByCategory(category.categoryId)"
  76. >{{ category.categoryName }}</a
  77. >
  78. </div>
  79. </div>
  80. <div class='item-tit-no' v-show='this.categoryList.length===0'>{{$t('shopInfo.noData')}}</div>
  81. </div>
  82. </div>
  83. <div
  84. class="menu"
  85. v-for="category in categoryList"
  86. :key="category.categoryId"
  87. >
  88. <a
  89. href="javascript:void(0);"
  90. @click="getProdListByCategory(category.categoryId)"
  91. class="menu-link"
  92. >{{ category.categoryName }}</a
  93. >
  94. </div>
  95. <!-- <div class="menu">
  96. <a href="javascript:void(0)" class="menu-link">热卖排行</a>
  97. </div>
  98. <div class="menu">
  99. <a href="javascript:void(0)" class="menu-link">臻美配饰</a>
  100. </div>
  101. <div class="menu">
  102. <a href="javascript:void(0)" class="menu-link">绅士男表</a>
  103. </div>
  104. <div class="menu">
  105. <a href="javascript:void(0)" class="menu-link">优雅女表</a>
  106. </div>
  107. <div class="menu">
  108. <a href="javascript:void(0)" class="menu-link">表白礼物</a>
  109. </div>-->
  110. </div>
  111. <div class="shop-search">
  112. <input type="text" class="s-input" v-model="prodName" />
  113. <input
  114. type="button"
  115. :value="$t('shopInfo.search')"
  116. class="s-btn"
  117. @click="getSearchProdPage(1)"
  118. />
  119. </div>
  120. </div>
  121. </div>
  122. <!--
  123. <div class="shop-banner">
  124. <img src="~/assets/img/banner.png" alt />
  125. </div>-->
  126. <!-- banner -->
  127. <div class="banner" v-if="banners.length > 0">
  128. <el-carousel height="450px" style="overflow-y: hidden;">
  129. <el-carousel-item v-for="banner in banners" :key="banner.imgUrl">
  130. <img
  131. :src="banner.imgUrl"
  132. style="width:100%;height:100%;"
  133. @click="imgToProd(banner)"
  134. />
  135. </el-carousel-item>
  136. </el-carousel>
  137. </div>
  138. <!-- /banner -->
  139. <div class="content">
  140. <div class="shop-content">
  141. <div class="tit" v-if="prodList.length > 0">
  142. <span class="bg-l"></span>
  143. {{ this.categoryName ? this.categoryName : $t('shopInfo.hotProducts') }}
  144. <span class="bg-r"></span>
  145. </div>
  146. <div class="goods-list">
  147. <div class="list-con">
  148. <!-- 商品 -->
  149. <div class="item" v-for="prod in prodList" :key="prod.prodId">
  150. <div class="goods-img" @click="toProdDetail(prod.prodId)">
  151. <img v-if="prod.pic" :src="prod.pic" alt />
  152. <img v-else src="~/assets/img/def.png" alt />
  153. </div>
  154. <div class="goods-msg" @click="toProdDetail(prod.prodId)">
  155. <div class="goods-name">{{ prod.prodName }}</div>
  156. <div class="goods-price">
  157. <div class="price">
  158. <span class="big"
  159. >{{ parsePrice(prod.price)[0] }}.{{
  160. parsePrice(prod.price)[1]
  161. }}</span
  162. >
  163. </div>
  164. </div>
  165. </div>
  166. </div>
  167. <!-- 商品 -->
  168. <div class="empty" v-if="prodList.length < 1">
  169. <div class="img">
  170. <img src="~/assets/images/emptyPic/not-found.png" alt />
  171. </div>
  172. <div v-if="prodList.length < 1 && shopInfo.shopStatus === 1" class="action">
  173. <div class="text">{{$t('sorryNoRelatedProducts')}}</div>
  174. <nuxt-link :to="Object.getOwnPropertyNames($route.query).length==1?'/':'/shopIndex?sid=' + shopId" class="btn">{{$t('lookAtOther')}}</nuxt-link>
  175. <nuxt-link to="/" class="btn-r">{{$t('shopInfo.mallHome')}}</nuxt-link>
  176. </div>
  177. <div v-if="shopInfo.shopStatus !== 1" class="action">
  178. <div class="text">{{$t('collection.storeReviewTips4')}}</div>
  179. <nuxt-link to="/" class="btn">{{$t('shopInfo.mallHome')}}</nuxt-link>
  180. </div>
  181. </div>
  182. </div>
  183. </div>
  184. <!-- 全部 -->
  185. <br />
  186. <div class="goods-list">
  187. <!-- 页码 -->
  188. <pagination
  189. v-model="current"
  190. :pages="pages"
  191. @changePage="getSearchProdPage"
  192. ></pagination>
  193. <!-- /页码 -->
  194. </div>
  195. </div>
  196. </div>
  197. </div>
  198. </template>
  199. <script>
  200. import Cookie from 'js-cookie'
  201. import PageUtil from '~/plugins/pageUtil'
  202. import { mapState } from 'vuex'
  203. import Pagination from '~/components/pagination'
  204. export default {
  205. components: {
  206. Pagination
  207. },
  208. data() {
  209. return {
  210. shopId: null //店铺id
  211. }
  212. },
  213. /**
  214. * pn: 商品名称
  215. * cid: 店铺分类id
  216. * sid: 店铺id
  217. * sort: 根据默认(0)/销量(1)/价格(2)排序
  218. * size: 每页的数据数量
  219. * ob: 0正序 1倒序
  220. * c: 当前第几页
  221. * @param query
  222. */
  223. async asyncData({ app, query, store }) {
  224. let [prodPage, categoryList, shopInfo, banners, shopNews] = await Promise.all([
  225. app.$axios.get(
  226. // query.st == 4 ? '/coupon/prodListByCouponId' : '/search/searchProdPage',
  227. query.st == 4 ? '/coupon/prodListByCouponId' : '/search/page',
  228. {
  229. //商品列表
  230. params: {
  231. sort: 12,
  232. size: 20,
  233. // orderBy: parseInt(query.ob) || 0,
  234. current: query.c ? query.c : 1,
  235. shopId: query.sid,
  236. couponId: query.couponId || '',
  237. keyword: query.pn || null,
  238. shopCategoryId: query.cid || '',
  239. isAllProdType: true,
  240. isActive: query.st != 4 ? 1 : undefined // 过滤掉活动商品
  241. }
  242. }
  243. ),
  244. app.$axios.get('/category/categoryInfo', {
  245. //店铺商品分类
  246. params: {
  247. shopId: query.sid,
  248. parentId: 0
  249. }
  250. }),
  251. app.$axios.get('/shop/headInfo', {
  252. //店铺头部信息
  253. params: {
  254. shopId: query.sid
  255. }
  256. }),
  257. app.$axios.get('/indexImgs/' + query.sid, {
  258. //轮播图
  259. params: {
  260. imgType: 1
  261. }
  262. }),
  263. app.$axios.get('/shop/notice/noticeList/' + query.sid, {
  264. //店铺公告
  265. params: {
  266. current: 1, //当前页
  267. size: 2
  268. }
  269. })
  270. ])
  271. var colled = null
  272. if (Cookie.get('token')) {
  273. colled = await app.$axios.get('/p/shop/collection/isCollection', {
  274. params: {
  275. shopId: query.sid
  276. }
  277. })
  278. }
  279. store.commit('shopCategory/SET_SHOPCATEGROY', categoryList.data)
  280. const curShopCategroy = categoryList.data.find(el => el.categoryId == query.cid)
  281. return {
  282. prodPage: prodPage.data,
  283. categoryList: categoryList.data,
  284. shopInfo: shopInfo.data,
  285. noticeList: shopNews.data.records,
  286. banners: banners.data,
  287. isCollection: colled?colled.data:colled,
  288. categoryId: query.cid ? query.cid : '',
  289. prodName: query.pn,
  290. current: query.c ? query.c : 1,
  291. categoryName: curShopCategroy ? curShopCategroy.categoryName : ''
  292. }
  293. },
  294. data() {
  295. return {
  296. shopId: this.$route.query.sid || 0,
  297. categoryId: '',
  298. prodName: '',
  299. page: {
  300. pages: 0, // 总页数
  301. rainbow: [] // 分页条
  302. },
  303. // pages: 0,
  304. categoryList: [],
  305. // prodList: [],
  306. prodPage: [],
  307. banners: [],
  308. isCollection: false,
  309. noticeList: []
  310. }
  311. },
  312. // 监听路径参数,监听的几个参数,若某一个值改变,则触发asyncData事件
  313. watchQuery: ['sid', 'cid', 'c', 'pn'],
  314. computed: {
  315. prodList() {
  316. console.log(this.prodPage)
  317. return this.$route.query.st == 4 ? this.prodPage.records : this.prodPage.records[0].products
  318. },
  319. pages() {
  320. return this.prodPage.pages
  321. }
  322. },
  323. mounted() {
  324. document.title = this.$i18n.t('shopInfo.storeHome')
  325. this.handleShopStatus()
  326. this.getInfo()
  327. this.getUserCollection()
  328. if(!this.shopId){
  329. this.$message({
  330. message: this.$t('userCenter.theStoreOffline'),
  331. duration: 1000,
  332. type: 'warning'
  333. });
  334. return
  335. }
  336. },
  337. methods: {
  338. /**
  339. * 店铺状态处理
  340. */
  341. handleShopStatus() {
  342. const shopStatus = this.shopInfo.shopStatus
  343. // 未开通/已删除
  344. if (shopStatus === -1) {
  345. this.$message({
  346. type: 'warning',
  347. message: this.$i18n.t('collection.storeReviewTips2'),
  348. duration: 1000,
  349. onClose: () => {
  350. this.$router.push({ path: '/' })
  351. }
  352. })
  353. return
  354. }
  355. // 停业中
  356. if (shopStatus === 0) {
  357. const contractStartTime = new Date(data.contractStartTime).getTime()
  358. const contractEndTime = new Date(data.contractEndTime).getTime()
  359. const today = new Date().getTime()
  360. // 1、店铺状态为0(停业中)时,当店铺未到签约开始时间,用户进入店铺提示:商家尚未营业
  361. if (today < contractStartTime) {
  362. this.$message({
  363. type: 'warning',
  364. message: this.$i18n.t('collection.storeReviewTips4'),
  365. duration: 1000,
  366. onClose: () => {
  367. this.$router.push({ path: '/' })
  368. }
  369. })
  370. return
  371. }
  372. // 2、店铺状态为0(停业中)时,当店铺超过签约有效期,用户进入店铺提示:商家已暂停未营业
  373. if (today > contractEndTime) {
  374. this.$message({
  375. type: 'warning',
  376. message: this.$i18n.t('collection.storeReviewTips5'),
  377. duration: 1000,
  378. onClose: () => {
  379. this.$router.push({ path: '/' })
  380. }
  381. })
  382. return
  383. }
  384. }
  385. // 已下线
  386. if (shopStatus === 2 || shopStatus === 3) {
  387. this.$message({
  388. type: 'warning',
  389. message: this.$i18n.t('collection.storeReviewTips3'),
  390. duration: 1000,
  391. onClose: () => {
  392. this.$router.push({ path: '/' })
  393. }
  394. })
  395. return
  396. }
  397. },
  398. /**
  399. * 跳转公告详情
  400. */
  401. toNewsDet(id) {
  402. this.$router.push({
  403. path: '/notice-detail',
  404. query: { id: id, shopId: this.shopId, shopName: this.shopInfo.shopName }
  405. })
  406. },
  407. /**
  408. * 跳转公告列表
  409. */
  410. toNewsList() {
  411. this.$router.push({
  412. path: '/notice-list',
  413. query: { shopId: this.shopId, shopName: this.shopInfo.shopName }
  414. })
  415. },
  416. /**
  417. * 获取店铺公告
  418. */
  419. getShopNews() {
  420. if(!this.shopId){
  421. this.$message({
  422. message: this.$t('userCenter.theStoreOffline'),
  423. duration: 1000,
  424. type: 'warning'
  425. });
  426. return
  427. }
  428. this.$axios
  429. .get('/shop/notice/noticeList/' + this.shopId, {
  430. params: {
  431. current: 1, //当前页
  432. size: 2
  433. }
  434. })
  435. .then(({ data }) => {
  436. this.noticeList = data.records
  437. })
  438. },
  439. /**
  440. * 获取店铺信息
  441. */
  442. getInfo() {
  443. if (!this.$route.query.sid) {
  444. this.shopId = this.shopInfo.shopId
  445. }
  446. // this.pages = this.prodPage.pages
  447. // this.prodList = this.prodPage.records
  448. // this.current = this.prodPage.current
  449. if (this.categoryId) {
  450. this.categoryList.forEach(category => {
  451. if (this.categoryId === category.categoryId.toString()) {
  452. this.categoryName = category.categoryName
  453. }
  454. })
  455. }
  456. },
  457. /**
  458. * 获取用户是否收藏此店铺
  459. */
  460. getUserCollection() {
  461. this.$axios
  462. .get('/p/shop/collection/isCollection', {
  463. params: {
  464. shopId: this.shopId
  465. }
  466. })
  467. .then(({ data }) => {
  468. this.isCollection = data
  469. })
  470. },
  471. /**
  472. * 收藏店铺/取消收藏
  473. */
  474. shopCollection() {
  475. this.$axios
  476. .post('/p/shop/collection/addOrCancel', this.shopId)
  477. .then(({ data }) => {
  478. if (data) {
  479. this.$message({
  480. message: this.$t('prodDetail.collectionSuccess'),
  481. type: 'success',
  482. duration: 1000
  483. })
  484. } else {
  485. this.$message({
  486. message: this.$t('prodDetail.uncollected'),
  487. duration: 1000
  488. })
  489. }
  490. this.getUserCollection()
  491. })
  492. },
  493. /**
  494. * 去到首页
  495. */
  496. homePage(){
  497. if(this.shopId){
  498. this.$router.push({ path: `/shopIndex?sid=${this.shopId}` })
  499. }else {
  500. this.$message({
  501. type: 'warning',
  502. message:this.$t('userCenter.theStoreOffline')
  503. })
  504. }
  505. },
  506. /**
  507. * 查询该分类下的商品
  508. */
  509. getProdListByCategory(categoryId) {
  510. if(this.shopId){
  511. if (!categoryId) {
  512. this.$router.push(`/shopIndex?sid=${this.shopId}`)
  513. } else {
  514. this.$router.push(`/shopIndex?sid=${this.shopId}&cid=${categoryId}`)
  515. }
  516. }else {
  517. this.$message({
  518. type: 'warning',
  519. message:this.$t('userCenter.theStoreOffline')
  520. })
  521. }
  522. },
  523. /**
  524. * 搜索商品/查询指定分页下的商品
  525. */
  526. getSearchProdPage(current) {
  527. let prodName = this.prodName ? this.prodName.trim() : ''
  528. var url = '/shopIndex?sid=' + this.shopId + '&c=' + current
  529. //通过商品名称搜索
  530. if (prodName) {
  531. url = url + '&pn=' + prodName
  532. }
  533. //在分类查询的基础上查询/分页
  534. if (this.categoryId) {
  535. url = url + '&cid=' + this.categoryId
  536. }
  537. // window.location.href = url
  538. this.$router.push( url )
  539. },
  540. /**
  541. * 轮播图跳转到商品
  542. */
  543. imgToProd(banner) {
  544. if(banner.type !== 0) {
  545. return
  546. }
  547. let prodId = banner.relation
  548. // 兼容火狐浏览器打开新窗口
  549. const newWindow = window.open()
  550. this.$axios
  551. .get('/prod/isStatus', {
  552. params: {
  553. prodId: prodId
  554. }
  555. })
  556. .then(({ data }) => {
  557. if (data) {
  558. this.toProdDetail(prodId, newWindow)
  559. }
  560. })
  561. },
  562. /**
  563. * 跳转到商品
  564. */
  565. toProdDetail(prodId, newWindow) {
  566. const params = {
  567. prodId,
  568. lang: this.$store.state.locale
  569. }
  570. const newPage = this.$router.resolve({ name: 'detail-prodId', query: params, params })
  571. if (newWindow) {
  572. newWindow.location.href = newPage.href
  573. } else {
  574. window.open(newPage.href, '_blank')
  575. }
  576. },
  577. /**
  578. * 价格处理
  579. */
  580. parsePrice: value => {
  581. var val = Number(value)
  582. if (!val) {
  583. val = 0
  584. }
  585. // 截取小数点后两位,并以小数点为切割点将val转化为数组
  586. return val.toFixed(2).split('.')
  587. }
  588. },
  589. // 监听id,要是发生变化就重新请求数据
  590. watch: {
  591. $route:(to, from)=>{
  592. // //要处理的操作
  593. // // console.log(this.queryId)
  594. // // let routeId = this.$route.query.sid
  595. // this.getShop(to.query.sid)
  596. // console.log(to.query.sid)
  597. // 路由变话页面刷新
  598. if(to.query.sid===from.query.sid) return
  599. location.reload()
  600. }
  601. }
  602. }
  603. </script>
  604. <style scoped src='~/assets/css/shop-index.css'></style>
  605. <style scoped>
  606. .el-pagination {
  607. text-align: right;
  608. padding: 0 30px;
  609. padding-top: 20px;
  610. }
  611. .pagination .el-pagination button,
  612. .el-pagination span:not([class*='suffix']) {
  613. padding: 0 8px !important;
  614. }
  615. .pagination .el-pagination.is-background .btn-next,
  616. .el-pagination.is-background .btn-prev,
  617. .el-pagination.is-background .el-pager li {
  618. background-color: #fff !important;
  619. }
  620. .pagination .el-pagination__editor.el-input .el-input__inner {
  621. width: 30px !important;
  622. }
  623. .empty .action .btn-r {
  624. display: inline-block;
  625. padding: 6px 18px;
  626. border: 1px solid #ddd;
  627. background: #f9f9f9;
  628. border-radius: 30px;
  629. margin-top: 20px;
  630. margin-left: 10px;
  631. color: #666;
  632. }
  633. .empty .action .btn-r:hover {
  634. background: #fff;
  635. }
  636. .goods-list .list-con .item .goods-msg .goods-name{
  637. height: 18px;
  638. }
  639. </style>