cuiyalong 5 роки тому
батько
коміт
4d40277297

+ 2 - 2
public/index.html

@@ -20,11 +20,11 @@
     <title><%= htmlWebpackPlugin.options.title %></title>
     <!-- 使用CDN的CSS文件 -->
     <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.css) { %>
-      <link rel="stylesheet" href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" />
+    <link rel="stylesheet" href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" />
     <% } %>
     <!-- 使用CDN的JS文件 -->
     <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.js) { %>
-      <script type="text/javascript" src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
+    <script type="text/javascript" src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
     <% } %>
   </head>
   <body>

+ 7 - 0
src/api/home.ts

@@ -17,4 +17,11 @@ export function entList2 (params: any) {
     method: 'get',
     params
   })
+}
+
+export function serviceTerms () {
+  return request({
+    url: '/jyapp/front/staticPage/dataExport_serviceterms.html',
+    method: 'get'
+  })
 }

+ 83 - 0
src/components/common/CountDownButton.vue

@@ -0,0 +1,83 @@
+<template>
+  <div class="countdown">
+    <van-button
+      class="countdown-button"
+      size="small"
+      :disabled="buttonDisabeld"
+      :loading="sLoading"
+      @click="buttonClick"
+    >{{ buttonText }}</van-button>
+  </div>
+</template>
+
+<script lang="ts">
+import { Component, Vue, Prop } from 'vue-property-decorator'
+import { Button } from 'vant'
+
+// @ is an alias to /src
+@Component({
+  name: 'countdown-button',
+  components: {
+    [Button.name]: Button
+  }
+})
+export default class CountdownButton extends Vue {
+  @Prop({ default: '发送验证码' }) defaultText: string | undefined;
+  @Prop({ default: false }) disabled: boolean | undefined;
+  @Prop({ default: 60 }) countdown: number | undefined;
+  @Prop({ default: false }) loading: boolean | undefined;
+
+  timerId = 0
+
+  count: any = 0
+
+  get buttonText () {
+    const dText = `${this.timerId ? '重新' : ''}${this.defaultText}`
+    return this.count <= 0 ? dText : `${this.count}s`
+  }
+
+  get sLoading () {
+    return this.loading
+  }
+
+  get buttonDisabeld () {
+    // 如果count不为0,则说明定时器一直在走
+    return !!this.count || this.disabled
+  }
+
+  buttonClick () {
+    this.$emit('click', this.startTimer)
+  }
+
+  startTimer () {
+    this.count = this.countdown
+    this.timerId = setInterval(() => {
+      this.count--
+      if (this.count <= 0) {
+        clearInterval(this.timerId)
+      }
+    }, 1000)
+  }
+
+  reset () {
+    clearInterval(this.timerId)
+    this.timerId = 0
+    this.count = 0
+  }
+}
+</script>
+
+<style lang="scss">
+.countdown {
+  .countdown-button {
+    color: #2ABED1;
+    font-size: 14px;
+    border: none;
+    // height: 35Px;
+    &[disabled] {
+      color: #9B9CA3;
+      opacity: 1;
+    }
+  }
+}
+</style>

+ 9 - 1
src/router/modules/home.ts

@@ -20,7 +20,7 @@ export default [
     name: 'buy',
     component: () => import(/* webpackChunkName: "index" */ '@/views/buy/Buy.vue'),
     meta: {
-      title: '购买'
+      title: '数据报告'
     }
   },
   {
@@ -30,5 +30,13 @@ export default [
     meta: {
       title: '支付'
     }
+  },
+  {
+    path: '/pay-success',
+    name: 'pay-success',
+    component: () => import(/* webpackChunkName: "pay" */ '@/views/pay/Pay.vue'),
+    meta: {
+      title: '支付结果'
+    }
   }
 ]

+ 2 - 1
src/store/index.ts

@@ -1,5 +1,6 @@
 import Vue from 'vue'
 import Vuex from 'vuex'
+import { isWeiXinBrowser } from '@/utils/globalFunctions.ts'
 
 if (process.env.NODE_DEV !== 'production') {
   Vue.use(Vuex)
@@ -19,7 +20,7 @@ export default new Vuex.Store({
     direction: 'forward', // 页面切换方向
     env: {
       // 运行环境是否是微信浏览器
-      isWeiXinBrowser: navigator.userAgent.toLowerCase().indexOf('micromessenger') !== -1
+      isWeiXinBrowser: isWeiXinBrowser()
     },
     defaultLayoutConf: {
       // layout标题,优先级高于$route.meta

+ 4 - 1
src/store/modules/home.ts

@@ -1,4 +1,7 @@
-// 列表数据保存模块
+import {
+  serviceTerms
+} from '@/api/home'
+
 export default {
   namespaced: true,
   state: {

+ 4 - 7
src/style/common.scss

@@ -5,6 +5,10 @@ $color_main: #2ABED1;
   color: $color_main;
 }
 
+input, textarea {
+  caret-color: $color_main;
+}
+
 // 8px
 .margin-top8 {
   margin-top: 8px;
@@ -13,13 +17,6 @@ $color_main: #2ABED1;
   margin-bottom: 8px;
 }
 
-// 清掉vant上下边框
-.van-border-none {
-  &:after {
-    border: none;
-  }
-}
-
 // 取消滚动条
 .no-scrollbar::-webkit-scrollbar {
   display: none;

+ 13 - 11
src/utils/globalFunctions.ts

@@ -117,7 +117,7 @@ export function dateFromNow (timestamp) {
 
 // 键盘抬起底部按钮隐藏
 // 传入输入框的DOM对象 和 footer的DOM对象
-export function inputFocusHideFooter (input: any, footer: any) {
+export function inputFocusHideFooter (inputs: Array<any>, footer: any) {
   const isShowBtn = function (f) {
     if (f) {
       footer.style.display = ''
@@ -132,17 +132,19 @@ export function inputFocusHideFooter (input: any, footer: any) {
 
   // 监听输入框的软键盘弹起和收起事件
   if (isIOS) {
-    input.addEventListener('focus', function () {
-      console.log('IOS 键盘弹出')
-      // IOS 键盘弹起后操作
-      isShowBtn(false)
-    }, false)
+    inputs.forEach((item, index) => {
+      item.addEventListener('focus', function () {
+        console.log('IOS 键盘弹出')
+        // IOS 键盘弹起后操作
+        isShowBtn(false)
+      }, false)
 
-    // IOS 键盘收起:IOS 点击输入框以外区域或点击收起按钮,输入框都会失去焦点,键盘会收起,
-    input.addEventListener('blur', () => {
-      console.log('IOS 键盘收起')
-      // IOS 键盘收起后操作
-      isShowBtn(true)
+      // IOS 键盘收起:IOS 点击输入框以外区域或点击收起按钮,输入框都会失去焦点,键盘会收起,
+      item.addEventListener('blur', () => {
+        console.log('IOS 键盘收起')
+        // IOS 键盘收起后操作
+        isShowBtn(true)
+      })
     })
   }
 

+ 0 - 1
src/utils/index.ts

@@ -1,4 +1,3 @@
 import './globalDirectives'
 import './globalFilters'
 // import './vConsole'
-

+ 266 - 8
src/views/buy/Buy.vue

@@ -1,24 +1,282 @@
 <template>
   <div class="report-buy">
     <div class="j-main">
-      介绍页面
+      <van-cell-group title="请填写订单信息">
+        <van-field v-model="userInfo.email" class="field" center placeholder="输入邮箱地址" @blur="checkPass('email')" :error-message="errorMsg.email" />
+        <transition name="van-slide-right">
+          <van-field v-show="true" class="field" center v-model="userInfo.code" @blur="checkPass('code')" placeholder="输入邮箱验证码" :error-message="errorMsg.code">
+            <template #button>
+              <!-- <countdown-button @click="sendCode" :countdown="120" :disabled="sendButtonDisabled"></countdown-button> -->
+              <countdown-button @click="sendCode" :countdown="120"></countdown-button>
+            </template>
+          </van-field>
+        </transition>
+        <van-field v-model="userInfo.phone" class="field" center type="tel" placeholder="输入手机号" @blur="checkPass('phone')" :error-message="errorMsg.phone" />
+        <van-field v-model="userInfo.company" class="field" center autosize @blur="checkPass('company')" type="textarea" rows="1"  maxlength="50" placeholder="输入公司名称" :error-message="errorMsg.company" />
+      </van-cell-group>
+      <div class="tips">
+        <p v-for="(item, index) in tipText" :key="index">*&nbsp;&nbsp;{{item}}</p>
+      </div>
     </div>
-    <div class="j-button-group j-footer">
-      <router-link tag="button" class="j-button-confirm" to="/pay">立即支付</router-link>
-      <!-- <button class="j-button-confirm">立即支付</button> -->
+    <div class="j-footer" ref="footer">
+      <div class="price-container">
+        <div class="price-top">
+          <span class="price-t-label">支付金额:</span>
+          <span class="price-t-count-now">
+            <span class="cn-l">&yen;</span>
+            <span class="cn-r">{{ orderInfo.price }}</span>
+          </span>
+        </div>
+        <div class="price-bottom">
+          <span class="price-b-label">原价:</span>
+          <span class="price-b-count-o">
+            <span class="co-l">&yen;</span>
+            <span class="co-r">{{ orderInfo.before_price }}</span>
+          </span>
+        </div>
+      </div>
+      <van-cell class="statement" clickable @click="toggleStatementState" center :border="false">
+        <template #icon>
+          <van-checkbox v-model="iAgreee" icon-size="17" checked-color="#2ABED1" ref="iAgreeeCheckbox" />
+        </template>
+        <template #title>
+          <p class="state">
+            <span>我已阅读,理解并接受</span>
+            <a class="link highlight-text" @click="serviceTerms" href="/jyapp/front/staticPage/dataExport_serviceterms.html">《剑鱼标讯线上购买与服务条款》</a>
+          </p>
+        </template>
+      </van-cell>
+      <div class="j-button-group">
+        <button class="j-button-confirm" @click="onSubmit" :disabled="confirmDisabled">立即支付</button>
+      </div>
     </div>
   </div>
 </template>
-<script>
+
+<script lang="ts">
 import { Component, Vue } from 'vue-property-decorator'
+import { Field, Cell, CellGroup, Checkbox, CheckboxGroup } from 'vant'
+import countdownButton from '@/components/common/CountDownButton.vue'
+import { inputFocusHideFooter } from '@/utils/globalFunctions'
 
 @Component({
-  name: 'buy'
+  name: 'buy',
+  components: {
+    [Field.name]: Field,
+    [Cell.name]: Cell,
+    [CellGroup.name]: CellGroup,
+    [Checkbox.name]: Checkbox,
+    [CheckboxGroup.name]: CheckboxGroup,
+    countdownButton
+  }
 })
 
-export default class Buy extends Vue {}
+export default class Buy extends Vue {
+  tipText = [
+    '数据报告将以邮件形式发至您的邮箱',
+    '数据报告一经购买不支持退货、退款',
+    '购买、售后等问题,请联系剑鱼标讯客服微信号:jianyu360'
+  ]
+
+  // 订单金额等数据
+  orderInfo = {
+    price: 123,
+    before_price: 2990
+  }
+
+  // 用户信息(需要提交)
+  userInfo = {
+    email: '',
+    phone: '',
+    code: '',
+    company: ''
+  }
+
+  allRegPass = false
+  iAgreee = false
+
+  // 错误提示信息
+  errorMsg = {
+    email: '',
+    phone: '',
+    code: '',
+    company: ''
+  }
+
+  // 错误提示验证对照表
+  errorMsgMap = {
+    email: {
+      reg: /\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/,
+      text: '邮箱格式输入错误'
+    },
+    phone: {
+      reg: /^(0|86|17951)?(13[0-9]|15[012356789]|166|17[3678]|18[0-9]|14[57])[0-9]{8}$/,
+      text: '手机号格式输入错误'
+    },
+    code: {
+      reg: '',
+      text: '验证码输入错误'
+    },
+    company: {
+      reg: '',
+      text: '必填项'
+    }
+  }
+
+  get confirmDisabled () {
+    return !this.iAgreee || !this.allRegPass
+  }
+
+  // get sendButtonDisabled () {
+  //   const type = 'email'
+  //   const reg = this.errorMsgMap[type].reg
+  //   const email = this.userInfo[type]
+  //   return !reg.test(email)
+  // }
+
+  toggleStatementState () {
+    this.iAgreee = !this.iAgreee
+  }
+
+  mounted () {
+    const inputs: any = document.querySelectorAll('.field .van-field__control')
+    inputFocusHideFooter(inputs, this.$refs.footer)
+  }
+
+  checkPass (type) {
+    const r = this.errorMsgMap[type]
+    const info = this.userInfo[type]
+    // 数据为空不显示校验失败提示,直接认定校验失败
+    this.checkAllPass()
+    if (!info) return false
+
+    let pass = true
+    if (r.reg) {
+      // 有正则的就根据正则替换
+      pass = r.reg.test(info)
+    } else {
+      // 判断是不是company
+      if (type === 'code') {
+        pass = !!info
+      } else if (type === 'company') {
+        // 判断是不是company
+        pass = !!info
+      }
+    }
+
+    if (pass) {
+      this.errorMsg[type] = ''
+    } else {
+      this.errorMsg[type] = this.errorMsgMap[type].text
+    }
+    return pass
+  }
+
+  checkAllPass () {
+    const info = this.userInfo
+    const regArr: any = []
+    for (const key in info) {
+      const r = this.errorMsgMap[key]
+      let pass = true
+      if (r.reg) {
+        // 有正则的就根据正则替换
+        pass = r.reg.test(info[key])
+      } else {
+        // 判断是不是company
+        if (key === 'code') {
+          pass = !!info[key]
+        } else if (key === 'company') {
+          pass = !!info[key]
+        }
+      }
+      // console.log(r, key, pass)
+      regArr.push(pass)
+    }
+    const f = regArr.indexOf(false) === -1
+    this.allRegPass = f
+    return f
+  }
+
+  serviceTerms () {
+    console.log('serviceTerms')
+  }
+
+  sendCode (cb) {
+    const reg = this.errorMsgMap.email.reg
+    const email = this.userInfo.email
+    const emailPass = reg.test(email)
+    if (!emailPass) return
+    cb && cb()
+    console.log('sendCode')
+  }
+
+  onSubmit () {
+    console.log(JSON.stringify(this.userInfo))
+  }
+}
 </script>
 
 <style lang="scss">
-  .report-buy {}
+  .report-buy {
+    .tips {
+      padding: 8px 14px;
+      color: #9B9CA3;
+      font-size: 12px;
+      line-height: 18px;
+    }
+    .field {
+      // min-width: 54px;
+      .van-field__body {
+        min-height: 30px;
+        font-size: 15px;
+        color: #171826;
+      }
+    }
+    .j-footer {
+      .price-container {
+        padding: 8px 16px 4px;
+        background-color: #fff;
+        .price-top {
+          display: flex;
+          align-items: center;
+          justify-content: space-between;
+        }
+        .price-t-label {
+          font-size: 13px;
+          color: #9B9CA3;
+        }
+        .price-t-count-now {
+          font-size: 20px;
+          color: #FB483D;
+          .cn-l {
+            margin-right: 4px;
+            font-size: 16px;
+          }
+        }
+
+        .price-bottom {
+          display: flex;
+          justify-content: flex-end;
+          margin-top: 3px;
+          font-size: 11px;
+          color: #9B9CA3;
+          line-height: 14px;
+          .co-r {
+            margin-left: 4px;
+            text-decoration: line-through;
+          }
+        }
+      }
+
+      .statement {
+        padding-top: 0;
+        padding-bottom: 0;
+        border: none;
+        font-size: 12px;
+        .van-cell__title {
+          margin-left: 8px;
+        }
+      }
+    }
+  }
 </style>

+ 40 - 5
src/views/pay/Pay.vue

@@ -1,21 +1,56 @@
 <template>
   <div class="j-pay">
     <div class="j-main">
-      支付
+      <div class="price-info">
+        <span class="info-text"></span>
+        <span class="price-count">
+          <span class="pc-l">&yen;</span>
+          <span class="pc-r">{{ orderInfo.price }}</span>
+        </span>
+      </div>
+      <van-radio-group v-model="radio">
+        <van-cell-group>
+          <van-cell title="单选框 1" clickable @click="radio = '1'">
+            <template #right-icon>
+              <van-radio name="1" />
+            </template>
+          </van-cell>
+          <van-cell title="单选框 2" clickable @click="radio = '2'">
+            <template #right-icon>
+              <van-radio name="2" />
+            </template>
+          </van-cell>
+        </van-cell-group>
+      </van-radio-group>
     </div>
     <div class="j-button-group j-footer">
-      <button class="j-button-confirm">立即支付</button>
+      <button class="j-button-confirm" @click="confirmPay">确认支付</button>
     </div>
   </div>
 </template>
-<script>
+<script lang="ts">
 import { Component, Vue } from 'vue-property-decorator'
+import { Cell, CellGroup, Radio, RadioGroup } from 'vant'
 
 @Component({
-  name: 'pay'
+  name: 'pay',
+  components: {
+    [Cell.name]: Cell,
+    [CellGroup.name]: CellGroup,
+    [Radio.name]: Radio,
+    [RadioGroup.name]: RadioGroup
+  }
 })
 
-export default class Pay extends Vue {}
+export default class Pay extends Vue {
+  orderInfo = {
+    price: '2020'
+  }
+
+  confirmPay () {
+    console.log(123)
+  }
+}
 </script>
 
 <style lang="scss">

+ 8 - 6
vue.config.js

@@ -19,19 +19,20 @@ const externals = {
   moment: 'moment'
 }
 
+// cdn地址获取访问(国外): https://www.jsdelivr.com/
+// cdn地址获取访问(国内): https://www.bootcdn.cn/
 const cdn = {
-  // 访问https://unpkg.com/element-ui/lib/theme-chalk/index.css获取最新版本
   css: [
     // '//unpkg.com/element-ui@2.10.1/lib/theme-chalk/index.css'
   ],
   js: [
-    '//cdn.bootcss.com/vue/2.6.11/vue.min.js',
-    '//cdn.bootcss.com/vue-router/3.1.3/vue-router.min.js',
-    '//cdn.bootcss.com/vuex/3.1.2/vuex.min.js',
     '//cdn.bootcss.com/axios/0.19.2/axios.min.js',
     '//cdn.bootcss.com/js-cookie/2.2.1/js.cookie.min.js',
     '//cdn.bootcdn.net/ajax/libs/moment.js/2.24.0/moment.min.js',
-    '//cdn.jsdelivr.net/npm/vant@2.5.7/lib/vant.min.js',
+    '//cdn.bootcss.com/vue/2.6.11/vue.min.js',
+    '//cdn.jsdelivr.net/npm/vue-router@3.1.5/dist/vue-router.min.js',
+    '//cdn.jsdelivr.net/npm/vuex@3.4.0/dist/vuex.min.js',
+    '//cdn.jsdelivr.net/npm/vant@2.8.2/lib/vant.min.js',
     '//res.wx.qq.com/open/js/jweixin-1.6.0.js'
   ]
 }
@@ -43,7 +44,8 @@ module.exports = {
   devServer: {
     proxy: {
       '^/testServer': {
-        target: 'http://192.168.3.207:8181/',
+        // target: 'http://192.168.3.207:8181/',
+        target: 'http://app2-jytest.jianyu360.cn',
         changeOrigin: true,
         logLevel: 'debug',
         pathRewrite: {