Pārlūkot izejas kodu

Merge branch 'dev/v1.0.98_tsz' of jianyu/web into feature/v1.0.98

汤世哲 5 mēneši atpakaļ
vecāks
revīzija
051027dc3f

+ 54 - 1
apps/bigmember_pc/src/api/modules/pay.js

@@ -1,5 +1,5 @@
-import request from '@/api'
 import qs from 'qs'
+import request from '@/api'
 
 export function getPhoneCaptcha() {
   return request({
@@ -75,3 +75,56 @@ export function getPDFPackBalance() {
     method: 'post',
   })
 }
+
+// 超级订阅赠送
+export function setTransferSubDuration(data) {
+  return request({
+    url: '/subscribepay/vip/gift/transferSubDuration',
+    method: 'post',
+    data: qs.stringify(data)
+  })
+}
+
+// 根据手机号获取可赠信息
+export function getInfoByPhone(data) {
+  return request({
+    url: '/subscribepay/vip/gift/getInfoByPhone',
+    method: 'post',
+    data: qs.stringify(data)
+  })
+}
+
+// 赠送人超级订阅可赠资源查询
+export function getSubDuration(data) {
+  return request({
+    url: '/subscribepay/vip/gift/getSubDuration',
+    method: 'post',
+    data: qs.stringify(data)
+  })
+}
+
+// 超级订阅赠送活动时间
+export function getConfigurationTime() {
+  return request({
+    url: '/subscribepay/vip/gift/configuration',
+    method: 'post'
+  })
+}
+
+// 超级订阅赠送记录查询
+export function getGiftRecordList(data) {
+  return request({
+    url: '/subscribepay/vip/gift/list',
+    method: 'post',
+    data: qs.stringify(data)
+  })
+}
+
+// 超级订阅赠送记录查询详情
+export function getGiftRecordDetail(data) {
+  return request({
+    url: '/subscribepay/vip/gift/informInfo',
+    method: 'post',
+    data: qs.stringify(data)
+  })
+}

+ 345 - 15
apps/bigmember_pc/src/components/dialog/GiftSubmitDialog.vue

@@ -5,45 +5,86 @@
     :title="title"
     class="gift-submit-dialog"
     :visible="visible"
-    @update:visible="update"
   >
     <div class="gift-submit-header">
       <div class="gift-submit-header__item">
         <span>订阅区域:</span>
-        <span>4个省</span>
+        <span>{{ subduration.areacount }}个省</span>
       </div>
       <div class="gift-submit-header__item">
         <span>可赠送时长(取整):</span>
-        <span>18个月</span>
+        <span>{{ subduration.gifted }}个月</span>
       </div>
     </div>
     <div class="gift-submit-body">
       <div class="gift-person-list-button">
         <span>人员列表</span>
-        <span class="gift-person-list-button__icon">+</span>
+        <span class="gift-person-list-button__icon" @click="addPerson">+</span>
       </div>
       <div class="gift-person-tip">
         说明:如手机号尚未注册剑鱼,赠送其超级订阅后,平台会自动帮其按照对应手机号注册。
       </div>
       <div class="gift-person-list">
-        <div class="gift-person-list__item">
-          <div class="gift-person-info">
-            <span>朋友手机号</span>
-            <el-input v-model="phone" class="custom-long-input" placeholder="请输入手机号" />
+        <div v-for="(item, index) in personList" :key="index" class="gift-person-list__item">
+          <el-form :ref="`form${index}`" :model="item" :rules="rules" class="gift-person-info-wrapper">
+            <el-form-item label="朋友手机号" prop="phone" class="gift-person-info">
+              <el-input
+                v-model="item.phone"
+                maxlength="11"
+                class="custom-long-input"
+                placeholder="请输入手机号"
+                @blur="validateSingleForm(index, item, 'phone')"
+              />
+            </el-form-item>
+            <el-form-item label="赠予时长" prop="monthnum" class="gift-person-info time">
+              <el-input
+                v-model="item.monthnum"
+                type="number"
+                class="custom-long-input"
+                placeholder="请输入整数"
+                @blur="validateSingleForm(index, item, 'monthnum')"
+              />
+              <span class="unit">个月</span>
+            </el-form-item>
+          </el-form>
+          <div v-show="index !== 0" class="delete-person" @click="deletePerson(index)">
+            <span class="icon-delete-button" />
           </div>
-          <div class="gift-person-info time">
-            <span>赠予时长</span>
-            <el-input v-model="monthnum" class="custom-long-input" placeholder="请输入整数" />
-            <span>个月</span>
+          <div v-if="item.status === -1" class="phone-no-register-tip">
+            {{ statusMessages[item.status] }}
+          </div>
+          <div v-else class="info-error-tip">
+            {{ statusMessages[item.status] }}
           </div>
         </div>
       </div>
+      <div class="gift-total-tip">
+        共赠送<span> {{ personList.length }} </span>人,赠送时长<span> {{ monthNumTotal }} </span>个月,剩余<span> {{ getGifted }} </span>个月可赠送
+      </div>
+      <div class="gift-read-agree">
+        <el-checkbox v-model="checked">
+          阅读并同意<a href="javascript:;">《“送好友超级订阅”产品须知》</a>
+        </el-checkbox>
+      </div>
     </div>
+    <span slot="footer" class="dialog-footer-wrapper">
+      <button
+        class="action-button confirm"
+        :disabled="!isFormValid"
+        @click="onClickConfirm"
+      >
+        提交
+      </button>
+      <button class="action-button cancel" @click="$emit('close')">
+        取消
+      </button>
+    </span>
   </CustomDialog>
 </template>
 
 <script>
 import CustomDialog from '@/components/dialog/Dialog.vue'
+import { getInfoByPhone, getSubDuration, setTransferSubDuration } from '@/api/modules/'
 
 export default {
   name: 'GiftSubmitDialog',
@@ -58,11 +99,201 @@ export default {
     },
   },
   data() {
+    const validatePhone = (rule, value, callback) => {
+      if (value === '') {
+        callback(new Error('请输入手机号'))
+      }
+      else if (!/^1[3-9]\d{9}$/.test(value)) {
+        callback(new Error('手机号码格式不正确'))
+      }
+      else {
+        callback()
+      }
+    }
+    const validateMonthnum = (rule, value, callback) => {
+      if (value === '') {
+        callback(new Error('请输入赠予时长'))
+      }
+      else if (value <= 0) {
+        callback(new Error('赠予时长应大于0'))
+      }
+      else {
+        callback()
+      }
+    }
     return {
+      checked: false,
+      personList: [
+        {
+          phone: '',
+          monthnum: '',
+          status: '',
+          error: '',
+          phoneValid: false,
+          monthnumValid: false
+        }
+      ],
+      rules: {
+        phone: [
+          { validator: validatePhone, trigger: 'blur' }
+        ],
+        monthnum: [
+          { validator: validateMonthnum, trigger: 'blur' },
+        ]
+      },
+      statusMessages: {
+        '1': '',
+        '-1': '提示:手机号尚未注册剑鱼,赠送其超级订阅后,平台会自动帮其按照对应手机号注册。',
+        '-2': '手机号已是超级订阅会员,且购买省份与当前省份不一致,不可赠送。',
+        '-3': '不能将超级订阅赠送给自己,请更换手机号。该提示展示在对应手机号下方'
+      },
+      subduration: {}
     }
   },
+  computed: {
+    isFormValid() {
+      return this.personList.every(item => item.phoneValid && item.monthnumValid)
+    },
+    monthNumTotal() {
+      return this.personList.reduce((total, item) => {
+        return total + Number(item.monthnum) || 0
+      }, 0)
+    },
+    // 剩余可赠送时长
+    getGifted() {
+      return Number(this.subduration.gifted) - this.monthNumTotal || 0
+    }
+  },
+  created() {
+    this.getSubDurationEvent()
+  },
   methods: {
-    update(e) {}
+    async getSubDurationEvent() {
+      const { error_code: code, data } = await getSubDuration()
+      if (code === 0) {
+        this.subduration = data
+      }
+    },
+    /**
+     * 验证单个表单
+     *
+     * @param {number} index - 表单的索引
+     */
+    validateSingleForm(index, item, fieldname) {
+      if (this.$refs[`form${index}`]) {
+        this.$refs[`form${index}`][0].validateField(fieldname, (error) => {
+          if (fieldname === 'phone') {
+            if (!error) {
+              // 需要只调用一次接口,避免多次请求
+              if (item.status !== 1) {
+                this.getInfoByPhoneEvent(index, item)
+              }
+            }
+            else {
+              item.phoneValid = false
+            }
+          }
+          else if (fieldname === 'monthnum') {
+            item.monthnumValid = !error
+          }
+        })
+      }
+    },
+    async getInfoByPhoneEvent(index, item) {
+      // 此处可以调用接口验证手机号是否已经注册剑鱼
+      try {
+        const { error_code: code, data } = await getInfoByPhone({
+          phone: item.phone
+        })
+        if (code === 0) {
+          item.status = data.status
+          item.error = this.statusMessages[data.status]
+          if (data.status === 1 || data.status === -1) {
+            item.phoneValid = true
+          }
+          else {
+            item.phoneValid = false
+          }
+          // 当data.status不等于1时,移除同组的赠予时长输入框校验结果
+          // if (data.status !== '1') {
+          //   this.$refs[`form${index}`][0].clearValidate('monthnum')
+          // }
+          // 当data.status不等于1时,检查personList中的每一项的status,如果有任何一个的status不等于1,提交按钮不能点击
+          // for (let i = 0; i < this.personList.length; i++) {
+          //   if (this.personList[i].status !== 1 && this.personList[i].status !== -1) {
+          //     this.isFormValid = false
+          //     return
+          //   }
+          // }
+        }
+      }
+      catch (error) {
+        console.log(error)
+        item.phoneValid = true
+      }
+    },
+    /**
+     * 更新整体表单的有效性
+     */
+    updateFormValidity() {
+      const validationPromises = this.personList.map((item, index) => {
+        return new Promise((resolve) => {
+          try {
+            this.$refs[`form${index}`][0].validate((valid) => {
+              resolve(valid)
+            })
+          }
+          catch (e) {
+            resolve(false)
+          }
+        })
+      })
+
+      Promise.all(validationPromises).then((results) => {
+        this.isFormValid = results.every(result => result)
+      })
+    },
+    addPerson() {
+      this.personList.push({
+        phone: '',
+        monthnum: '',
+        status: '',
+        error: '',
+        phoneValid: false,
+        monthnumValid: false
+      })
+      this.updateFormValidity()
+    },
+    /**
+     * 删除指定索引位置的人员
+     *
+     * @method deletePerson
+     */
+    deletePerson(index) {
+      this.personList.splice(index, 1)
+      this.updateFormValidity()
+    },
+    onClickConfirm() {
+      if (!this.checked)
+        return this.$toast('请勾选协议')
+      if (this.isFormValid) {
+        this.confirmGiftData()
+      }
+    },
+    async confirmGiftData() {
+      // 参数格式:{18439509554: 1,18439509555: 2}
+      const data = this.personList.reduce((acc, cur) => {
+        if (cur.phone && cur.monthnum) {
+          acc[cur.phone] = cur.monthnum
+        }
+        return acc
+      }, {})
+      const { error_code: code } = await setTransferSubDuration(data)
+      if (code === 0) {
+        this.$toast('赠送成功')
+        this.$emit('close')
+      }
+    }
   }
 }
 </script>
@@ -131,24 +362,123 @@ export default {
             padding: 10px;
             border: 1px solid #ECECEC;
             border-radius: 8px;
+            overflow-y: auto;
             .gift-person-list__item {
+              position: relative;
               display: flex;
-              justify-content: space-between;
-              align-items: center;
+              flex-direction: column;
+              justify-content: center;
+              margin-bottom: 10px;
               padding: 10px 20px;
+              width: 480px;
               border-radius: 8px;
               background: linear-gradient(to bottom, #F6F6F6, #fff);
+              .gift-person-info-wrapper {
+                display: flex;
+                align-items: center;
+                .el-form-item {
+                  margin-bottom: 0;
+                }
+                .el-form-item__label {
+                  font-size: 14px;
+                  line-height: 22px;
+                  color: #1D1D1D;
+                  &::before {
+                    content: '';
+                  }
+                }
+              }
+              .delete-person {
+                position: absolute;
+                right: -30px;
+                top: 0;
+                .icon-delete-button {
+                  display: inline-block;
+                  width: 20px;
+                  height: 20px;
+                  background: url('~@/assets/images/icon-delete.png') no-repeat;
+                  background-size:20px 20px ;
+                  cursor: pointer;
+                }
+              }
             }
             .gift-person-info {
               font-size: 14px;
               color: #1D1D1D;
+              &.time {
+                position: relative;
+                margin-left: 24px;
+                width: 120px;
+                .unit {
+                  position: absolute;
+                  top: 30px;
+                  right: -40px;
+                }
+              }
             }
             .custom-long-input {
               margin-top: 8px;
+              height: 36px;
+              .el-input__inner {
+                height: 36px;
+                line-height: 36px;
+              }
+            }
+            .phone-no-register-tip, .info-error-tip {
+              margin-top: 10px;
+              font-size: 14px;
+              line-height: 22px;
+              color: #2ABED1;
+            }
+            .info-error-tip {
+              color: #FF3A20;
+            }
+          }
+          .gift-total-tip {
+            margin: 10px 0;
+            font-size: 14px;
+            line-height: 22px;
+            color: #686868;
+            span {
+              color: #2ABED1;
+            }
+          }
+          .gift-read-agree {
+            font-size: 14px;
+            color: #686868;
+            .el-checkbox.is-checked {
+              .el-checkbox__label {
+                color: #888888;
+              }
+            }
+            a {
+              color: #2ABED1;
+              text-decoration: none;
             }
           }
         }
       }
+      .dialog-footer {
+        justify-content: center;
+      }
+    }
+    .dialog-footer-wrapper {
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      button {
+        width: 132px;
+        height: 36px;
+        background: #2ABED1;
+        color: #fff;
+        font-size: 16px;
+        border: none;
+        &.cancel {
+          background: #fff;
+          color: #1D1D1D;
+          border: 1px solid #E0E0E0;
+        }
+      }
     }
   }
 </style>

+ 6 - 5
apps/bigmember_pc/src/views/workspace/components/AccountInfo.vue

@@ -98,7 +98,7 @@
       </div>
     </div>
     <!-- 引导赠送好友超级订阅 -->
-    <div v-if="isShowGift" class="gift-tip">
+    <div class="gift-tip">
       <span>支持送好友超级订阅</span>
       <span class="gift-link" @click="goGiftLink">送给朋友></span>
     </div>
@@ -106,6 +106,7 @@
 </template>
 
 <script>
+import { mapState } from 'vuex'
 import { getUserAccountShow } from '@/api/modules/'
 
 export default {
@@ -118,15 +119,15 @@ export default {
     }
   },
   computed: {
+    ...mapState('user', ['info']),
+
     attr() {
       return this.accountInfo.attr || {}
-    },
-    isShowGift() {
-      return this.accountInfo.vipType === '注册用户' || this.accountInfo.vipType === '超级订阅'
     }
   },
   mounted() {
     this.getAccount()
+    console.log(this.info, 'this.info')
   },
   methods: {
     goGiftLink() {
@@ -135,7 +136,7 @@ export default {
         // 弹窗提醒购买超级订阅后赠送好友
         this.$emit('showGiftDialog', 'buy')
       }
-      else if (this.accountInfo.vipType === '超级订阅') {
+      else if (this.info.vipStatus > 0) {
         const isOneMonthPassed = this.isOneMonthPassed(this.accountInfo.vipEntTime)
         if (isOneMonthPassed) {
           // 弹窗提醒超级订阅不满一个月续费后赠送好友

+ 1 - 1
apps/bigmember_pc/src/views/workspace/dashboard.vue

@@ -53,7 +53,7 @@
         </button>
       </span>
     </GiftDialog>
-    <GiftSubmitDialog :visible="showGiftSubmit" />
+    <GiftSubmitDialog :visible="showGiftSubmit" @close="showGiftSubmit = false" />
   </el-container>
 </template>