cinema.vue 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. <template>
  2. <scroll-view scroll-y class="cinema">
  3. <view class='topbar'>
  4. <topbar>
  5. <view class="topbar-box">
  6. <view class="left-box" @click="goPage(`/pages/cinema/citylist?cityList=${JSON.stringify(cityList)}`,null,{cityList:cityList})">
  7. <van-icon name="location" />
  8. <text>{{address}}</text>
  9. <van-icon name="arrow-down" />
  10. </view>
  11. <van-search class='top-search' shape="round" background="#fff" placeholder="请输入电影名称" @search="onSearch" @change='onSearchChange' />
  12. </view>
  13. </topbar>
  14. </view>
  15. <view class="tabs-box">
  16. <van-tabs :active='tabActive' animated sticky offset-top='87' @change='tabsChange'>
  17. <van-tab title="热映">
  18. <loadSke :loading='hotLoading' :list='hotList'>
  19. <view class="flex-box">
  20. <view @click="goPage(`/pages/cinema/cinemalist?filmId=${item.filmId}&cityId=${cityId}&location=${location}`)"
  21. class="film-box" v-for="(item,index) in hotList" :key='item.filmId'>
  22. <image :src="item.pic" mode="scaleToFill" class="img" draggable></image>
  23. <view class="bottom-box">
  24. <view class="tit">
  25. <text class="text-1">{{item.name}}</text>
  26. <text class="text-2">{{item.grade ?'评分'+item.grade : '暂无评分'}}</text>
  27. </view>
  28. <view class="des-box">
  29. <view class="des">{{item.filmTypes}}</view>
  30. <view class="des">{{item.cast}}</view>
  31. </view>
  32. <button type="default" class="buy">
  33. 购 票
  34. </button>
  35. </view>
  36. </view>
  37. </view>
  38. </loadSke>
  39. </van-tab>
  40. <van-tab title="影院">
  41. <loadSke :loading='cinemaLoading' :list='cinemaList'>
  42. <view class="cinema-box" v-for="(item,index) in cinemaList" :key='item.cinemaId' @click='goPage(`/pages/cinema/schedulelist?cinemaId=${item.cinemaId}&filmId=${filmId}`)'>
  43. <view class="tit">
  44. <text>{{item.cinemaName}}</text>
  45. <text class="text-2">{{item.distance}}km</text>
  46. </view>
  47. <text class="address">{{item.address}}</text>
  48. </view>
  49. </loadSke>
  50. </van-tab>
  51. <van-tab title="即将上映">
  52. <loadSke :loading='soonLoading'>
  53. <view class="soon-box" v-for="(ObjItem,ObjIndex) in soonList" :key='ObjIndex'>
  54. <view class="tit-text">
  55. <van-icon class='icon' name="https://t1-1305573081.cos.ap-shanghai.myqcloud.com/wxapp/static/imgs/%E6%97%A5%E6%9C%9F.png" />
  56. {{ObjIndex}}
  57. </view>
  58. <view class="flex-box">
  59. <view class="film-box" v-for="(item,index) in ObjItem" :key='item.filmId'>
  60. <image :src="item.pic" mode="scaleToFill" class="img" draggable></image>
  61. <view class="bottom-box">
  62. <view class="tit">
  63. <text class="text-1">{{item.name}}</text>
  64. <text class="text-2">{{item.grade ?'评分'+item.grade : '暂无评分'}}</text>
  65. </view>
  66. <view class="des-box">
  67. <view class="des">{{item.filmTypes}}</view>
  68. <view class="des">{{item.cast}}</view>
  69. </view>
  70. </view>
  71. </view>
  72. </view>
  73. </view>
  74. </loadSke>
  75. </van-tab>
  76. </van-tabs>
  77. </view>
  78. </scroll-view>
  79. </template>
  80. <script>
  81. import loadSke from '@/components/skeleton/index/index.vue'
  82. import {
  83. getPayData
  84. } from '@/api/pay.js'
  85. import {
  86. amapRegeo
  87. } from '@/api/amap.js'
  88. import {
  89. getHotList,
  90. getSoonList,
  91. getCityList,
  92. getInfo,
  93. getFilmDiscount,
  94. getCinemaList
  95. } from '@/api/cinema.js'
  96. export default {
  97. components: {
  98. loadSke
  99. },
  100. data: () => ({
  101. tabActive: 0,
  102. hotList: [],
  103. soonList: {},
  104. hotLoading: true,
  105. soonLoading: true,
  106. location: [119.131390, 26.150210],
  107. cityList: [],
  108. address: '定位中',
  109. cinemaList: {},
  110. cinemaLoading: true
  111. }),
  112. async mounted() {
  113. this.setFilmDiscount()
  114. await this.getLocation()
  115. this.address = this.$store.state.cinema.cityObj.regionName;
  116. this.init()
  117. this.cinemaListInit()
  118. },
  119. computed: {
  120. cityId() {
  121. return this.$store.state.cinema.cityId;
  122. }
  123. },
  124. watch: {
  125. cityId() {
  126. this.address = this.$store.state.cinema.cityObj.regionName;
  127. this.init()
  128. this.cinemaListInit()
  129. }
  130. },
  131. methods: {
  132. onSearch(e){
  133. console.log(e)
  134. },
  135. onSearchChange(e){
  136. console.log(e)
  137. },
  138. tabsChange(e) {
  139. this.tabActive = e.detail.index
  140. },
  141. setFilmDiscount() {
  142. getFilmDiscount().then(res => {
  143. this.$store.commit('SET_FILMDISCOUNT', res.data)
  144. })
  145. },
  146. async getLocation() {
  147. let location = await wx.getLocation()
  148. this.location = [location.longitude.toFixed(6), location.latitude.toFixed(6)]
  149. let address = await amapRegeo({
  150. location: this.location.toString()
  151. })
  152. let cityListRes = await getCityList()
  153. let cityList = cityListRes.data.data.list
  154. let cityObj = {}
  155. cityList.map((val) => {
  156. cityObj[val.pinYin] || (cityObj[val.pinYin] = [])
  157. cityObj[val.pinYin].push(val)
  158. if (val.regionName == address.regeocode.addressComponent.city.slice(0, -1)) {
  159. this.selectCity(val)
  160. }
  161. })
  162. this.cityList = cityObj
  163. },
  164. async init() {
  165. this.hotLoading = true
  166. this.soonLoading = true
  167. let hotListRes = await getHotList({
  168. cityId: this.cityId
  169. })
  170. this.hotList = hotListRes.data.data.list
  171. this.$nextTick(()=>{
  172. this.hotLoading = false
  173. })
  174. let soonListRes = await getSoonList({
  175. cityId: this.cityId
  176. })
  177. let soonListObj = {}
  178. soonListRes.data.data.list.forEach((val) => {
  179. soonListObj[val.publishDate.slice(0, 10)] || (soonListObj[val.publishDate.slice(0, 10)] = [])
  180. soonListObj[val.publishDate.slice(0, 10)].push(val)
  181. })
  182. this.soonList = soonListObj
  183. this.$store.commit('SET_FILMLIST', this.hotList.concat(soonListRes.data.data.list))
  184. this.$nextTick(()=>{
  185. this.soonLoading = false
  186. })
  187. },
  188. async cinemaListInit() {
  189. this.cinemaLoading = true
  190. let showListRes = await getCinemaList({
  191. cityId: this.cityId,
  192. latitude: this.location[1],
  193. longitude: this.location[0],
  194. })
  195. showListRes.data.data.list.map(val => {
  196. val.distance = (Math.sqrt((val.latitude - this.location[1]) ** 2 + (val.longitude - this.location[0]) ** 2) *
  197. 111).toFixed(2)
  198. return val
  199. })
  200. showListRes.data.data.list.sort(function(a, b) {
  201. return a.distance - b.distance
  202. })
  203. this.cinemaList = showListRes.data.data.list
  204. this.cinemaLoading = false
  205. },
  206. selectCity(obj) {
  207. this.$store.commit('SET_CITYOBJ', obj)
  208. this.$store.commit('SET_CITYID', obj.cityId)
  209. }
  210. }
  211. }
  212. </script>
  213. <style scoped lang="scss">
  214. .cinema{
  215. height: 100%;
  216. position: relative;
  217. }
  218. .topbar {
  219. position: fixed;
  220. top: 0;
  221. left: 0;
  222. right: 0;
  223. z-index: 1;
  224. .topbar-box {
  225. display: flex;
  226. align-items: center;
  227. .left-box {
  228. min-width: 150rpx;
  229. display: flex;
  230. justify-content: center;
  231. align-items: center;
  232. margin-left: 20rpx;
  233. text{
  234. white-space: nowrap;
  235. }
  236. }
  237. }
  238. }
  239. .tabs-box{
  240. margin-top: 160rpx;
  241. }
  242. .cinema-box {
  243. padding: 30rpx;
  244. border-top: 1rpx solid #E8E8E8;
  245. background-color: #FFFFFF;
  246. display: flex;
  247. flex-direction: column;
  248. .tit {
  249. display: flex;
  250. justify-content: space-between;
  251. .text-1 {
  252. font-size: 30rpx;
  253. color: #0F0404;
  254. }
  255. .text-2 {
  256. font-size: 26rpx;
  257. color: #999999;
  258. white-space: nowrap;
  259. }
  260. }
  261. .address {
  262. margin-top: 20rpx;
  263. width: 600rpx;
  264. font-size: 26rpx;
  265. color: #666666;
  266. white-space: nowrap;
  267. overflow: hidden;
  268. text-overflow: ellipsis;
  269. }
  270. }
  271. .tab {
  272. display: flex;
  273. justify-content: space-around;
  274. align-items: stretch;
  275. background-color: #FFFFFF;
  276. position: sticky;
  277. top: 0;
  278. left: 0;
  279. z-index: 1;
  280. .text {
  281. padding: 30rpx 0;
  282. font-size: 30rpx;
  283. color: #0F0404;
  284. }
  285. .hover {
  286. border-bottom: 6rpx solid red;
  287. }
  288. .location-box {
  289. padding: 30rpx 0;
  290. font-size: 30rpx;
  291. color: #0F0404;
  292. display: flex;
  293. justify-content: center;
  294. align-items: center;
  295. }
  296. }
  297. .flex-box {
  298. display: flex;
  299. justify-content: space-between;
  300. flex-wrap: wrap;
  301. background: #FFFFFF;
  302. margin-top: 1rpx;
  303. padding: 0rpx 20rpx;
  304. padding-bottom: 20rpx;
  305. .film-box {
  306. width: 334rpx;
  307. border-radius: 20rpx;
  308. overflow: hidden;
  309. background: #FFFFFF;
  310. margin: 30rpx 11rpx 0;
  311. box-shadow: 0px 2px 16px 0px rgba(68, 6, 6, 0.2);
  312. .img {
  313. width: 100%;
  314. height: 456rpx;
  315. }
  316. .bottom-box {
  317. padding: 30rpx 20rpx;
  318. .tit {
  319. display: flex;
  320. justify-content: space-between;
  321. .text-1 {
  322. width: 200rpx;
  323. font-size: 26rpx;
  324. overflow: hidden;
  325. text-overflow: ellipsis;
  326. white-space: nowrap;
  327. }
  328. .text-2 {
  329. font-size: 26rpx;
  330. color: #ED4F24;
  331. white-space: nowrap;
  332. }
  333. }
  334. .des-box {
  335. margin-top: 20rpx;
  336. .des {
  337. width: 100%;
  338. font-size: 22rpx;
  339. color: #666666;
  340. overflow: hidden;
  341. text-overflow: ellipsis;
  342. white-space: nowrap;
  343. }
  344. }
  345. .buy {
  346. margin-top: 30rpx;
  347. width: 126rpx;
  348. height: 60rpx;
  349. background: linear-gradient(90deg, #E31818, #ED3E24, #ED4F24);
  350. border-radius: 30rpx;
  351. font-size: 26rpx;
  352. font-weight: 400;
  353. color: #FFFFFF;
  354. display: flex;
  355. justify-content: center;
  356. align-items: center;
  357. white-space: nowrap;
  358. }
  359. }
  360. }
  361. }
  362. .soon-box {
  363. margin-top: 20rpx;
  364. .tit-text {
  365. background-color: #FFF0E5;
  366. padding: 28rpx 55rpx;
  367. font-size: 26rpx;
  368. font-weight: bold;
  369. color: #0F0404;
  370. display: flex;
  371. align-items: center;
  372. .icon {
  373. margin-right: 20rpx;
  374. }
  375. }
  376. }
  377. </style>