index.vue 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  1. <template>
  2. <app-layout>
  3. <app-tab-nav :setTop="0" :border="false" :shadow="false" :height="100" :tabList="tabList" :padding="0" :activeItem="activeTab" @click="tabStatus" :theme="getTheme"></app-tab-nav>
  4. <view v-if="activeTab == '0'" class="scan">
  5. <view>输入兑换码或者扫码兑换二维码开始兑换</view>
  6. <view class="scan-input">
  7. <input @focus="hiddenBottom=false" @blur="hiddenBottom=true" placeholder="请输入兑换码" v-model="code" type="text">
  8. <image v-if="!is_not_wechat" @click="scan" src="./../image/scan.png"></image>
  9. </view>
  10. <view @click="clerk" class="scan-button" :style="{'background-color': code.length > 0 ? getTheme.background : '#d6d6d6','color' : code.length > 0 ? '#fff' : '#b2b2b2'}">兑换</view>
  11. </view>
  12. <view v-if="activeTab == '1'">
  13. <view v-if="list.length > 0" class="item" v-for="(item,index) in list" :key="index">
  14. <view class="main-between cross-center status">
  15. <view class="item-code" :style="{'background-color': item.status == 2 ? getTheme.background_o : '#F5F5F5','color' : item.status == 2 ? getTheme.color : '#999999'}">{{item.code}}</view>
  16. <view @click="toDetail(item)" class="dir-left-nowrap cross-center item-status" :style="{'color': item.status == 2 ? getTheme.color : '#999999'}">
  17. <view>{{item.status == 2 ? item.last_num + '项待领取' : '已全部领取'}}</view>
  18. <i v-if="item.status == 2" :style="{'color': getTheme.color}" class="iconfont icon-right">&#xe7eb;</i>
  19. <image v-else src="/static/image/icon/right.png"></image>
  20. </view>
  21. </view>
  22. <view class="item-time">兑换时间:{{item.r_raffled_at}}</view>
  23. </view>
  24. <view style="padding-top: 30%" v-if="list.length == 0">
  25. <app-no-goods title="暂无兑换记录" :is_image="1" background="#f7f7f7"></app-no-goods>
  26. </view>
  27. </view>
  28. <view @click="showRule" class="use-info" :style="{'color': getTheme.color}" :class="[`${tabbarbool? 'tabbarbool':''}`]" v-if="setting.is_rules == 1 && activeTab == '0' && hiddenBottom">使用说明</view>
  29. <u-mask :show="dialog" :maskClickAble="false" :zoom="false">
  30. <view class="dialog">
  31. <image class="dialog-img" src="./../image/error.png"></image>
  32. <view class="dialog-msg">
  33. <text>{{msg}}</text>
  34. </view>
  35. <view class="dialog-other">{{other}}</view>
  36. <view @click="dialog=false;code=''" :style="{'background-color': getTheme.background}" class="dialog-button">我知道了</view>
  37. </view>
  38. </u-mask>
  39. <view v-if="showRules" class="dialog-bg">
  40. <view class="u-rules" :animation="animationData" :style="{bottom: bottom}" :class="[`${tabbarbool? 'tabbarbool':''}`,`${iphone_x? 'iphone_x':''}`]">
  41. <view class="u-rules-top dir-right-nowrap">
  42. <view v-if="over" @click="showRules=false;bottom='-998rpx';animationData={}" class="end-close main-center cross-center">
  43. <image src="/static/image/icon/icon-close.png"></image>
  44. </view>
  45. </view>
  46. <view class="u-rules-content">
  47. <parse :content="setting.rules"></parse>
  48. </view>
  49. </view>
  50. </view>
  51. <view @click="toGift" v-if="setting.is_to_gift == 1 && hiddenBottom" class="jump-dialog cross-center dir-top-nowrap main-center" :class="[`${tabbarbool? 'tabbarbool':''}`]">
  52. <image :src="setting.to_gift_pic"></image>
  53. <view>礼品卡</view>
  54. </view>
  55. </app-layout>
  56. </template>
  57. <script>
  58. import appTabNav from "../../../components/basic-component/app-tab-nav/app-tab-nav.vue";
  59. import uMask from '../../../components/basic-component/u-mask/u-mask.vue';
  60. import parse from "../../../components/basic-component/app-rich/parse.vue";
  61. import appNoGoods from '../../../components/page-component/app-no-goods/app-no-goods.vue';
  62. import { mapState, mapGetters } from "vuex";
  63. export default {
  64. name: "index",
  65. data() {
  66. return {
  67. currentRoute: this.$platDiff.route(),
  68. tabbarbool: false,
  69. iphone_x: false,
  70. tabList: [
  71. {id:0, name: '兑换礼品'},
  72. {id:1, name: '兑换记录'}
  73. ],
  74. over: false,
  75. hiddenBottom: true,
  76. code: '',
  77. bottom: '-998rpx',
  78. activeTab: '0',
  79. list: [],
  80. setting: {},
  81. animationData: {},
  82. showRules: false,
  83. dialog: false,
  84. more: false,
  85. loading: false,
  86. is_not_wechat: false,
  87. msg: '',
  88. other: '',
  89. page: 1,
  90. };
  91. },
  92. watch: {
  93. tabBarNavs: {
  94. handler: function() {
  95. this.b();
  96. },
  97. immediate: true,
  98. }
  99. },
  100. components: {
  101. "app-tab-nav": appTabNav,
  102. parse,
  103. "app-no-goods": appNoGoods,
  104. "u-mask": uMask
  105. },
  106. computed: {
  107. ...mapState({
  108. tabBarNavs: state => state.mallConfig.navbar.navs,
  109. }),
  110. ...mapGetters('mallConfig', {
  111. getTheme: 'getTheme'
  112. })
  113. },
  114. // #ifdef MP
  115. onShareAppMessage() {
  116. return this.$shareAppMessage({
  117. title: this.$children[0].navigationBarTitle,
  118. path: "/plugins/exchange/index/index",
  119. });
  120. },
  121. // #endif
  122. // #ifdef MP-WEIXIN
  123. onShareTimeline() {
  124. // 分享朋友圈beta
  125. return this.$shareTimeline({
  126. title: this.$children[0].navigationBarTitle,
  127. query: {} // 此处填写页面的参数
  128. });
  129. },
  130. // #endif
  131. onReachBottom() {
  132. if(this.more) {
  133. this.page++;
  134. this.getMore();
  135. }
  136. },
  137. onLoad(options) { this.$commonLoad.onload(options);
  138. let that = this;
  139. // #ifdef H5
  140. this.is_not_wechat = !this.$jwx.isWechat();
  141. // #endif
  142. if(options.code) {
  143. that.code = options.code
  144. }
  145. if(options.token && options.library_id && options.created_at) {
  146. that.getActive(options.token, options.library_id, options.created_at)
  147. }
  148. // #ifdef MP-WEIXIN
  149. wx.showShareMenu({
  150. menus: ['shareAppMessage', 'shareTimeline']
  151. })
  152. // #endif
  153. uni.getSystemInfo({
  154. success: function (res) {
  155. that.height = -res.screenHeight;
  156. if(res.model.indexOf('iPhone X') > -1 || res.model.indexOf('iPhone 11') > -1 || res.model.indexOf('iPhone11') > -1 || res.model.indexOf('iPhone12') > -1 || res.model.indexOf('Unknown Device') > -1) {
  157. that.iphone_x = true;
  158. }
  159. }
  160. });
  161. that.$request({
  162. url: that.$api.exchange.setting,
  163. }).then(response=>{
  164. if(response.code == 0) {
  165. that.setting = response.data;
  166. }else {
  167. uni.showToast({
  168. title: response.msg,
  169. icon: 'none',
  170. duration: 1000
  171. });
  172. }
  173. })
  174. },
  175. onShow() {
  176. if(this.activeTab == '1') {
  177. this.getList();
  178. }
  179. },
  180. methods: {
  181. getActive(token, library_id, created_at) {
  182. let that = this;
  183. uni.showLoading({
  184. mask: true,
  185. title: '获取兑换码...'
  186. });
  187. that.$request({
  188. url: that.$api.exchange.code,
  189. data: {
  190. token: token,
  191. library_id: library_id,
  192. created_at: created_at,
  193. }
  194. }).then(response=>{
  195. uni.hideLoading();
  196. this.loading = false;
  197. if(response.code == 0) {
  198. this.code = response.data.code
  199. }else {
  200. this.msg = response.msg;
  201. this.other = '';
  202. this.dialog = true;
  203. }
  204. }).catch(response => {
  205. uni.hideLoading();
  206. });
  207. },
  208. b() {
  209. // #ifndef H5
  210. let currentRoute = this.currentRoute;
  211. for (let i = 0; i < this.tabBarNavs.length; i++) {
  212. if(currentRoute.includes(this.tabBarNavs[i].url.split('?')[0])) {
  213. return this.tabbarbool = true;
  214. }
  215. }
  216. // #endif
  217. return this.tabbarbool = false;
  218. },
  219. showRule() {
  220. let that = this;
  221. that.over = false;
  222. that.showRules = true;
  223. var animation = uni.createAnimation({
  224. duration: 1000,
  225. timingFunction: 'ease',
  226. })
  227. that.animationData = animation
  228. setTimeout(function(){
  229. let num = 0;
  230. if(that.tabbarbool) {
  231. num += 55
  232. }
  233. animation.bottom(-500).bottom(num).step()
  234. that.animationData = animation.export();
  235. setTimeout(function(){
  236. that.bottom = num *2 + 'rpx';
  237. that.over = true;
  238. },1200)
  239. },200)
  240. },
  241. scan() {
  242. let that = this;
  243. // #ifndef MP-ALIPAY || H5
  244. uni.scanCode({
  245. success(res) {
  246. if(res.scanType == "CODE_128" || (res.result && res.result.length == 12)) {
  247. that.code = res.result
  248. } else {
  249. if(res.path) {
  250. uni.showLoading({
  251. mask: true,
  252. title: '获取兑换码...'
  253. });
  254. let path = res.path
  255. path = path.split('?');
  256. let scene = path[1];
  257. let reg = new RegExp("scene=", "g");
  258. scene = path[1].replace(reg, "");
  259. that.$request({
  260. url: that.$api.default.qrcode_parameter,
  261. data: {
  262. token: scene
  263. }
  264. }).then(response => {
  265. if (response.code === 0) {
  266. if(response.data.detail && response.data.detail.data.type == 'auto') {
  267. that.getActive(response.data.detail.data.token, response.data.detail.data.library_id, response.data.detail.data.created_at)
  268. }else {
  269. uni.hideLoading();
  270. uni.showToast({
  271. title: '未获取到兑换码',
  272. icon: 'none',
  273. duration: 1000
  274. });
  275. that.code = response.data.detail.data.code;
  276. }
  277. }
  278. });
  279. }else {
  280. uni.showToast({
  281. title: '暂不支持此二维码,请使用应用内扫一扫功能',
  282. icon: 'none',
  283. duration: 1000
  284. });
  285. }
  286. }
  287. }
  288. })
  289. // #endif
  290. // #ifdef MP-ALIPAY
  291. my.ap.navigateToAlipayPage({
  292. appCode:'alipayScan',
  293. success:(res) => {
  294. },
  295. fail:(res) => {
  296. my.alert({content:'失败:'+JSON.stringify(res)});
  297. }
  298. });
  299. // #endif
  300. // #ifdef H5
  301. if (this.$jwx.isWechat()) {
  302. this.$jwx.scanQRCode({
  303. success(res) {
  304. if(res.resultStr) {
  305. if(res.resultStr.indexOf(',') > 0){
  306. //条形码时返回的格式类似为【code128,123456789】
  307. var dealserialNumber=res.resultStr.split(',')[1];
  308. dealserialNumber = dealserialNumber.replace(/[^a-z\d]/ig, "");//处理条形码扫描的字符
  309. that.code = dealserialNumber;//扫描结果传递到的处理页面
  310. }else{
  311. //二维码时
  312. location.href=res.resultStr;//扫描结果传递到的处理页面
  313. }
  314. }else if(res.scanType == "CODE_128" || (res.result && res.result.length == 12)) {
  315. that.code = res.result
  316. } else {
  317. if(res.path) {
  318. uni.showLoading({
  319. mask: true,
  320. title: '获取兑换码...'
  321. });
  322. let path = res.path
  323. path = path.split('?');
  324. let scene = path[1];
  325. let reg = new RegExp("scene=", "g");
  326. scene = path[1].replace(reg, "");
  327. that.$request({
  328. url: that.$api.default.qrcode_parameter,
  329. data: {
  330. token: scene
  331. }
  332. }).then(response => {
  333. if (response.code === 0) {
  334. if(response.data.detail.data.type == 'auto') {
  335. that.getActive(response.data.detail.data.token, response.data.detail.data.library_id, response.data.detail.data.created_at)
  336. }else {
  337. uni.hideLoading();
  338. that.code = response.data.detail.data.code;
  339. }
  340. }
  341. });
  342. }else {
  343. uni.showToast({
  344. title: '暂不支持此二维码,请使用应用内扫一扫功能',
  345. icon: 'none',
  346. duration: 1000
  347. });
  348. }
  349. }
  350. }
  351. })
  352. }else {
  353. uni.showToast({
  354. title: '暂不支持浏览器点击扫码,请应用扫一扫功能',
  355. icon: 'none',
  356. duration: 1000
  357. });
  358. }
  359. // #endif
  360. },
  361. tabStatus(e) {
  362. if(this.loading) {
  363. return false
  364. }
  365. this.list = [];
  366. this.page = 1;
  367. this.activeTab = e.currentTarget.dataset.id;
  368. this.getList();
  369. },
  370. getMore() {
  371. let that = this;
  372. if(this.loading) {
  373. return false
  374. }
  375. this.loading = true;
  376. that.more = false;
  377. uni.showLoading({
  378. mask: true,
  379. title: '加载中...'
  380. });
  381. that.$request({
  382. url: that.$api.exchange.log,
  383. data: {
  384. page: that.page
  385. }
  386. }).then(response=>{
  387. uni.hideLoading();
  388. this.loading = false;
  389. if(response.code == 0) {
  390. that.list = that.list.concat(response.data.list);
  391. if(that.list.length == response.data.pagination.pageSize) {
  392. that.more = true;
  393. }
  394. }else {
  395. uni.showToast({
  396. title: response.msg,
  397. icon: 'none',
  398. duration: 1000
  399. });
  400. }
  401. }).catch(response => {
  402. uni.hideLoading();
  403. });
  404. },
  405. getList() {
  406. let that = this;
  407. if(this.loading) {
  408. return false
  409. }
  410. this.loading = true;
  411. that.page = 1;
  412. that.more = false;
  413. uni.showLoading({
  414. mask: true,
  415. title: '加载中...'
  416. });
  417. that.$request({
  418. url: that.$api.exchange.log
  419. }).then(response=>{
  420. this.loading = false;
  421. uni.hideLoading();
  422. if(response.code == 0) {
  423. that.list = response.data.list;
  424. if(that.list.length == response.data.pagination.pageSize) {
  425. that.more = true;
  426. }
  427. }else {
  428. uni.showToast({
  429. title: response.msg,
  430. icon: 'none',
  431. duration: 1000
  432. });
  433. }
  434. }).catch(response => {
  435. uni.hideLoading();
  436. });
  437. },
  438. toDetail(item) {
  439. uni.navigateTo({
  440. url: '/plugins/exchange/detail/detail?code=' + item.code + '&exchange=1'
  441. })
  442. },
  443. toGift() {
  444. uni.navigateTo({
  445. url: '/plugins/exchange/list/list'
  446. })
  447. },
  448. clerk() {
  449. let that = this;
  450. if(this.loading || !this.code) {
  451. return false
  452. }
  453. uni.showLoading({
  454. mask: true,
  455. title: '兑换中...'
  456. });
  457. this.loading = true;
  458. let code = this.code;
  459. that.$request({
  460. url: that.$api.exchange.info,
  461. data: {
  462. code: code
  463. }
  464. }).then(response=>{
  465. this.loading = false;
  466. uni.hideLoading();
  467. if(response.code == 0) {
  468. this.code = '';
  469. uni.navigateTo({
  470. url: '/plugins/exchange/detail/detail?code=' + code
  471. })
  472. }else {
  473. this.msg = response.msg;
  474. this.other = '';
  475. if(response.msg == '该兑换码未到使用时间!') {
  476. this.other = response.data.valid_start_time + '-' + response.data.valid_end_time + ' 可用'
  477. }
  478. this.dialog = true;
  479. }
  480. }).catch(response => {
  481. uni.hideLoading();
  482. });
  483. }
  484. }
  485. }
  486. </script>
  487. <style scoped lang="scss">
  488. .dialog-bg {
  489. position: fixed;
  490. top: 0;
  491. left: 0;
  492. width: 100%;
  493. height: 100%;
  494. background-color: rgba(0,0,0,.3);
  495. z-index: 101;
  496. }
  497. .jump-dialog {
  498. position: fixed;
  499. bottom: 120rpx;
  500. right: 24rpx;
  501. width: 100rpx;
  502. height: 100rpx;
  503. border-radius: 50%;
  504. background-color: rgba(0,0,0,.3);
  505. font-size: 16rpx;
  506. color: #fff;
  507. z-index: 100;
  508. &.tabbarbool {
  509. bottom: 240rpx;
  510. }
  511. image {
  512. width: 54rpx;
  513. height: 54rpx;
  514. margin-bottom: 3rpx;
  515. display: block;
  516. }
  517. }
  518. .use-info {
  519. position: fixed;
  520. bottom: 64rpx;
  521. text-align: center;
  522. font-size: 28rpx;
  523. width: 200rpx;
  524. margin: 0 auto;
  525. left: 0;
  526. right: 0;
  527. &.tabbarbool {
  528. bottom: 204rpx;
  529. }
  530. }
  531. .scan {
  532. position: absolute;
  533. top: 0;
  534. left: 0;
  535. width: 100%;
  536. height: 100%;
  537. background-color: #fff;
  538. text-align: center;
  539. padding-top: 184rpx;
  540. font-size: 28rpx;
  541. color: #353535;
  542. .scan-input {
  543. height: 94rpx;
  544. width: 580rpx;
  545. margin: 40rpx auto;
  546. background-color: #f9f9f9;
  547. border: 2rpx solid #e2e2e2;
  548. border-radius: 16rpx;
  549. position: relative;
  550. box-shadow: 1rpx 1rpx 4rpx 4rpx #f5f5f5;
  551. input {
  552. border-radius: 16rpx;
  553. width: 100%;
  554. height: 100%;
  555. padding: 10rpx 80rpx 10rpx 20rpx;
  556. text-align: left;
  557. }
  558. image {
  559. width: 48rpx;
  560. height: 44rpx;
  561. position: absolute;
  562. right: 24rpx;
  563. top: 23rpx;
  564. z-index: 2
  565. }
  566. }
  567. .scan-button {
  568. height: 300rpx;
  569. width: 300rpx;
  570. border-radius: 50%;
  571. text-align: center;
  572. line-height: 300rpx;
  573. box-shadow: 2rpx 2rpx 8rpx 8rpx #f3f3f3;
  574. margin: 112rpx auto;
  575. font-size: 42rpx;
  576. font-weight: 600;
  577. color: #fff;
  578. }
  579. }
  580. .item {
  581. margin: 24rpx 24rpx 0;
  582. background-color: #fff;
  583. border-radius: 16rpx;
  584. .status {
  585. padding: 28rpx 30rpx;
  586. border-bottom: 2rpx solid #e2e2e2;
  587. .item-code {
  588. padding: 16rpx 30rpx;
  589. border-radius: 40rpx;
  590. font-size: 28rpx;
  591. font-weight: 600;
  592. }
  593. .item-status {
  594. font-size: 28rpx;
  595. view:first-of-type {
  596. margin-right: 16rpx;
  597. }
  598. image {
  599. height: 22rpx;
  600. width: 14rpx;
  601. display: block;
  602. }
  603. }
  604. }
  605. .item-time {
  606. height: 72rpx;
  607. line-height: 72rpx;
  608. font-size: 28rpx;
  609. color: #666666;
  610. padding: 0 30rpx;
  611. }
  612. }
  613. .dialog {
  614. margin: 270rpx auto;
  615. background-color: #fff;
  616. border-radius: 16rpx;
  617. width: 600rpx;
  618. padding: 60rpx 0;
  619. text-align: center;
  620. .dialog-img {
  621. width: 200rpx;
  622. height: 200rpx;
  623. margin: 0 auto 20rpx;
  624. }
  625. .dialog-msg {
  626. font-size: 32rpx;
  627. color: #353535;
  628. }
  629. .dialog-other {
  630. font-size: 24rpx;
  631. color: #999999;
  632. }
  633. .dialog-button {
  634. font-size: 26rpx;
  635. width: 520rpx;
  636. height: 90rpx;
  637. border-radius: 45rpx;
  638. line-height: 90rpx;
  639. text-align: center;
  640. color: #fff;
  641. margin: 50rpx auto 0;
  642. }
  643. }
  644. .u-rules {
  645. border-top-left-radius: 16rpx;
  646. border-top-right-radius: 16rpx;
  647. width: 100%;
  648. position: fixed;
  649. z-index: 1005;
  650. left: 0;
  651. background-color: #fff;
  652. &.iphone_x.tabbarbool {
  653. padding-bottom: 50rpx;
  654. }
  655. .u-rules-top {
  656. border-top-left-radius: 16rpx;
  657. border-top-right-radius: 16rpx;
  658. background-color: #fff;
  659. height: 80rpx;
  660. .end-close {
  661. width: 80rpx;
  662. height: 80rpx;
  663. padding: 25rpx;
  664. image {
  665. width: 30rpx;
  666. height: 30rpx;
  667. }
  668. }
  669. }
  670. .u-rules-content {
  671. padding: 0 20rpx;
  672. min-height: 160rpx;
  673. max-height: 918rpx;
  674. overflow: auto;
  675. }
  676. }
  677. </style>