浏览代码

feat:增加推送设置页面

yangfeng 2 年之前
父节点
当前提交
e4fb0438b4

+ 40 - 0
src/api/modules/subscribe.js

@@ -187,3 +187,43 @@ export function getMsgDistributor (data) {
     data: data
   })
 }
+
+// 用户绑定信息获取
+export function getUserBindInfo (data) {
+  return request({
+    baseURL: '/jyapi/jybx',
+    url: '/subscribe/getUser',
+    method: 'post',
+    data: data
+  })
+}
+
+// 用户绑定信息获取
+export function setUserBindInfo (data) {
+  return request({
+    baseURL: '/jyapi/jybx',
+    url: '/subscribe/setUser',
+    method: 'post',
+    data: data
+  })
+}
+
+// 用户推送设置信息获取
+export function getUserPushInfo (data) {
+  return request({
+    baseURL: '/jyapi/jybx',
+    url: '/subscribe/getPushSet',
+    method: 'post',
+    data: data
+  })
+}
+
+// 用户推送设置信息设置
+export function setUserPushInfo (data) {
+  return request({
+    baseURL: '/jyapi/jybx',
+    url: '/subscribe/setPushSet',
+    method: 'post',
+    data: data
+  })
+}

二进制
src/assets/images/channel-1.png


二进制
src/assets/images/channel-2.png


二进制
src/assets/images/channel-3.png


二进制
src/assets/images/doload-app-code.png


二进制
src/assets/images/icon/set-default.png


+ 49 - 0
src/assets/js/selector.js

@@ -547,3 +547,52 @@ export const hospitalNatureExp = [
     children: []
   }
 ]
+
+// 24小时数组
+export const hoursData = ['00:00', '01:00', '02:00', '03:00', '04:00', '05:00', '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00', '19:00', '20:00', '21:00', '22:00', '23:00']
+
+// 推送功能
+export const pushFunctionData = [
+  {
+    type: 'o_subset',
+    name: '我的订阅',
+    desc: '根据订阅条件,向您推送相关招投标公告信息。',
+    showEdit: true
+  },
+  {
+    type: 'o_follow_project',
+    name: '项目进度监控',
+    desc: '关注项目如有动态变更,将为您推送。',
+    showEdit: false
+  },
+  {
+    type: 'o_follow_ent',
+    name: '企业情报监控-企业中标动态',
+    desc: '关注企业一旦中标,会推送企业的中标项目、时间等公告信息。',
+    showEdit: false
+  },
+  {
+    type: 'o_entinfo',
+    name: '企业情报监控-企业工商变动',
+    desc: '通过大数据和AI智能分析预测到与您有关的潜在项目时,可及时收到提醒信息。',
+    showEdit: false
+  },
+  {
+    type: 'o_newproject_forecast',
+    name: '潜在项目预测',
+    desc: '根据订阅条件,向您推送相关招投标公告信息。',
+    showEdit: false
+  },
+  {
+    type: 'o_week_report',
+    name: '周报',
+    desc: '根据为您推送的招标项目信息,提供每周多维度分析报告。',
+    showEdit: false
+  },
+  {
+    type: 'o_month_report',
+    name: '月报',
+    desc: '根据为您推送的招标项目信息,提供每月多维度分析报告。',
+    showEdit: false
+  }
+]

+ 12 - 3
src/components/dialog/Dialog.vue

@@ -4,12 +4,17 @@
     :custom-class="customClass"
     v-bind="$props"
     :visible="visible"
-    @update:visible="update">
+    @update:visible="update"
+    @open="$emit('open')"
+    @opened="$emit('opened')"
+    @close="$emit('close')"
+    @closed="$emit('closed')"
+  >
     <slot name="default"></slot>
     <span slot="footer" class="dialog-footer">
       <slot name="footer">
         <button class="action-button cancel" @click="onClickCancel">取消</button>
-        <button class="action-button confirm" @click="onClickConfirm">确定</button>
+        <button class="action-button confirm"  :disabled="disabled" @click="onClickConfirm">确定</button>
       </slot>
     </span>
     </el-dialog>
@@ -46,7 +51,8 @@ export default {
     customClass: {
       type: String,
       default: ''
-    }
+    },
+    disabled: Boolean
   },
   methods: {
     update (e) {
@@ -93,6 +99,9 @@ export default {
       border: 1px solid $color_main;
       background-color: $color_main;
       color: #fff;
+      &:disabled{
+        opacity: 0.5;
+      }
     }
     &:not(:last-of-type) {
       margin-right: 48px;

+ 182 - 0
src/components/push-setting/setList.vue

@@ -0,0 +1,182 @@
+<template>
+  <div class="fun-list">
+    <div class="f-l-left">
+      <h4 class="list-name">{{ name }}</h4>
+      <p class="list-desc">{{ desc }}</p>
+    </div>
+    <div class="f-l-middle">
+      <div class="switch-item">
+        <span>邮件提醒</span>
+        <el-switch
+          :value="emailVal"
+          active-color="#2ABED1"
+          inactive-color="#E3E4E5"
+          :active-value="1"
+          :inactive-value="0"
+          @change="onEmailChange"
+        >
+        </el-switch>
+        </div>
+      <div class="switch-item" v-if="isWxShow">
+        <span>微信提醒</span>
+        <el-switch
+          v-model="wxVal"
+          active-color="#2ABED1"
+          inactive-color="#E3E4E5"
+          :active-value="1"
+          :inactive-value="0"
+          @change="onWxChange"
+        >
+        </el-switch>
+      </div>
+    </div>
+    <div class="f-l-right">
+      <span>{{ way }}</span>
+      <span v-if="showEdit" class="edit-text" @click="onEdit">编辑</span>
+    </div>
+  </div>
+</template>
+
+<script>
+import { Switch } from 'element-ui'
+export default {
+  name: 'funList',
+  props: {
+    index: [Number, String],
+    type: String,
+    name: String,
+    desc: String,
+    mailPush: [Number, Boolean],
+    wxPush: [Number, Boolean],
+    appPush: [Number, Boolean],
+    isWxShow: [Boolean, Number],
+    showEdit: Boolean,
+    rateMode: [Number, String],
+    times: Array,
+    way: String,
+    wxBind: Boolean,
+    emailBind: [Boolean, String]
+  },
+  components: {
+    [Switch.name]: Switch
+  },
+  data () {
+    return {
+      emailVal: this.mailPush,
+      wxVal: this.wxPush
+    }
+  },
+  watch: {
+    mailPush (newVal) {
+      this.emailVal = newVal
+    },
+    wxPush (newVal) {
+      this.wxVal = newVal
+    }
+  },
+  methods: {
+    onEdit () {
+      this.$emit('edit', {
+        rateMode: this.rateMode,
+        times: this.times,
+        type: this.type
+      })
+    },
+    onEmailChange (val) {
+      if (this.emailBind) {
+        this.emailVal = val
+      } else {
+        this.emailVal = 0
+      }
+      this.$emit('emailChange', {
+        index: this.index,
+        bind: this.emailBind,
+        val: this.emailVal,
+        type: this.type
+      })
+    },
+    onWxChange (val) {
+      if (this.wxBind) {
+        this.wxVal = val
+      } else {
+        this.wxVal = false
+      }
+      this.$emit('wxChange', {
+        index: this.index,
+        bind: this.wxBind,
+        val: this.wxVal,
+        type: this.type
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.fun-list{
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 12px 0;
+  &:not(:last-child){
+    box-shadow: inset 0px -1px 0px rgba(0, 0, 0, 0.05);
+  }
+  .flex-center{
+    display: flex;
+    align-items: center;
+    padding: 0 16px;
+    text-align: left;
+  }
+  .f-l-left {
+    width: 44%;
+    @extend .flex-center;
+    flex-direction: column;
+    align-items: flex-start;
+  }
+  .f-l-middle{
+    width: 32%;
+    white-space: nowrap;
+    @extend .flex-center;
+  }
+  .f-l-right{
+    width: 26%;
+    font-size: 14px;
+    line-height: 22px;
+    color: #1D1D1D;
+    @extend .flex-center;
+    justify-content: space-between;
+  }
+  .list-name{
+    font-size: 16px;
+    line-height: 24px;
+    color: #1D1D1D;
+  }
+  .list-desc{
+    margin-top: 8px;
+    font-size: 14px;
+    line-height: 22px;
+    color: #686868;
+  }
+  .switch-item{
+    display: flex;
+    align-items: center;
+    margin-right: 36px;
+    font-size: 14px;
+    line-height: 18px;
+    color: #000000;
+    > span{
+      margin-right: 12px;
+    }
+  }
+  .edit-text{
+    flex-shrink: 0;
+    color: #2ABED1;
+    cursor: pointer;
+  }
+}
+::v-deep{
+  .el-switch__core{
+    width: 48px!important;
+  }
+}
+</style>

+ 70 - 0
src/components/switch/index.vue

@@ -0,0 +1,70 @@
+<script>
+import { Switch } from 'element-ui'
+/**
+  *
+  * element-switch组件增强,支持在状态改变前拦截change事件
+  *
+  * 用法和element-switch一样
+  *
+  * {Function} beforeChange 同步拦截change事件
+  *
+  * {Function} beforePromiseChange 异步拦截change事件
+  *
+  */
+export default {
+  name: 'SwitchComponent',
+  extends: Switch,
+  props: {
+    beforeChange: Function,
+    beforePromiseChange: Function,
+    data: {
+      type: Object,
+      default () {
+        return {}
+      }
+    }
+  },
+  data () {
+    return {}
+  },
+  watch: {},
+  methods: {
+    handleChange () {
+      const _this = this
+      const val = _this.checked ? _this.inactiveValue : _this.activeValue
+      const data = _this.data
+      // 如果有配置beforeChange那么return true才不会拦截后续动作
+      if (_this.beforeChange) {
+        if (_this.beforeChange(data)) {
+          _this.checkChange(val)
+        }
+      } else if (_this.beforePromiseChange) {
+        // 如果有配置beforePromiseChange那么resolve();才不会拦截后续动作
+        _this.beforePromiseChange(data).then(() => {
+          _this.checkChange(val)
+        })
+      } else {
+        _this.checkChange(val)
+      }
+    },
+    // 拦截拦截状态改变后处理相关逻辑
+    checkChange (val) {
+      const _this = this
+      // 抛出事件
+      _this.$emit('input', val)
+      _this.$emit('change', val)
+      _this.$nextTick(() => {
+        _this.$refs.input.checked = _this.checked
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+::v-deep{
+  .el-switch__core{
+    width: 48px!important;
+  }
+}
+</style>

+ 2 - 1
src/router/router-interceptors.js

@@ -27,7 +27,8 @@ const powerCheckWhiteList = [
   'datapack_buy',
   'buy-data-export', // 使用路由别名时候的兼容处理
   'buy-big-member',
-  'buy-data-pack'
+  'buy-data-pack',
+  'push_setting'
 ]
 
 const regListCheck = function (regList, path) {

+ 6 - 0
src/router/routers.js

@@ -185,5 +185,11 @@ export default [
     path: '/medical/distributor_followed',
     name: 'distributor_follow',
     component: () => import('@/views/medical/distributorFollowed.vue')
+  },
+  // 推送设置
+  {
+    path: '/push_setting',
+    name: 'push_setting',
+    component: () => import('@/views/push-setting/index.vue')
   }
 ]

+ 6 - 0
src/views/SubPush.vue

@@ -6,6 +6,7 @@
         <div class="header-right">
           <el-button v-if="!canUsePageFilterUser" @click="toBuySvip" class="sub-manager" type="plain" icon="el-icon-jy-vip">开通超级订阅</el-button>
           <el-button v-if="showManageButton" @click="goManage" class="sub-manager" type="plain" icon="el-icon-jy-edit">订阅管理</el-button>
+          <el-button @click="goPushSet" class="sub-manager" type="plain" icon="el-icon-jy-set-default">推送设置</el-button>
         </div>
       </div>
       <div class="max-push-tip red" v-show="tip.maxPushTip">
@@ -894,6 +895,9 @@ export default {
           }
         }
       } catch (error) {}
+    },
+    goPushSet () {
+      openSelfLink(this.$router.resolve('/push_setting'))
     }
   }
 }
@@ -902,6 +906,7 @@ export default {
 <style lang="scss" scoped>
   @include diy-icon('vip', 38, 18);
   @include diy-icon('edit', 20, 20);
+  @include diy-icon('set-default', 20, 20);
   .in-app {
     margin: 0 12px;
     .page--sub-push {
@@ -1331,6 +1336,7 @@ export default {
         &:not(:last-of-type) {
           margin-right: 20px;
         }
+        margin-left: 0;
       }
     }
     .visibility-hidden {

+ 681 - 0
src/views/push-setting/index.vue

@@ -0,0 +1,681 @@
+<template>
+  <div class="push-setting">
+    <h2 class="title">推送设置</h2>
+    <div class="push-card channel">
+      <div class="card-title">推送渠道设置</div>
+      <div class="card-container">
+        <div class="card-item">
+          <div class="card-item-bg">
+            <img src="@/assets/images/channel-1.png" alt="">
+          </div>
+          <div class="card-item-desc">邮件提醒:根据设置的推送时间发送邮件</div>
+          <div class="card-item-handle">
+            <span>邮箱:<em v-if="bind.email">{{ bind.email }}</em></span>
+            <span class="edit-text" v-if="bind.email" @click="onBindEmail('edit')">编辑</span>
+            <span class="main-color" v-else @click="onBindEmail('bind')">立即绑定</span>
+          </div>
+        </div>
+        <div class="card-item">
+          <div class="card-item-bg">
+            <img src="@/assets/images/channel-2.png" alt="">
+          </div>
+          <div class="card-item-desc">微信提醒:根据设置的推送时间通过微信公众号发送消息</div>
+          <div class="card-item-handle">
+            <span>微信公众号:</span>
+            <span v-if="bind.wx">已关注</span>
+            <el-popover
+              v-else
+              width="200"
+              popper-class="custom-popover"
+              :append-to-body="false"
+              placement="bottom"
+              trigger="hover"
+            >
+              <div class="wx-public-container">
+                <img :src="bind.wxCodeUrl" width="108" height="108" alt="微信公众号">
+                <p class="wx-public-tip">使用 <span class="hight-text">微信</span> 扫码关注,开启推送</p>
+              </div>
+              <span class="main-color" slot="reference">立即关注</span>
+            </el-popover>
+          </div>
+        </div>
+        <div class="card-item">
+          <div class="card-item-bg">
+            <img src="@/assets/images/channel-3.png" alt="">
+          </div>
+          <div class="card-item-desc">APP提醒:根据设置的推送时间发送APP消息</div>
+          <div class="card-item-handle main-color">
+            <el-popover
+              width="200"
+              popper-class="custom-popover"
+              :append-to-body="false"
+              placement="bottom"
+              trigger="hover"
+            >
+              <div class="wx-public-container">
+                <img src="@/assets/images/doload-app-code.png" width="108" height="108" alt="app下载">
+                <p class="wx-public-tip">扫一扫下载剑鱼标讯APP</p>
+              </div>
+              <span class="main-color" slot="reference">立即下载剑鱼标讯APP</span>
+            </el-popover>
+          </div>
+        </div>
+      </div>
+    </div>
+    <div class="push-card function">
+      <div class="card-title">推送功能</div>
+      <div class="card-main">
+        <div class="fun-head">
+          <p>通知项</p>
+          <p>推送渠道<span class="gray-color">(APP提醒设置请前往APP操作)</span></p>
+          <p>推送时间</p>
+        </div>
+        <div class="fun-container">
+          <SetList
+            ref="funList"
+            v-for="(item, index) in usableList"
+            :key="index"
+            v-bind="item"
+            :index="index"
+            :wx-bind="bind.wx"
+            :email-bind="bind.email"
+            @edit="onPushTimeEdit"
+            @wxChange="onSwitchWx"
+            @emailChange="onSwitchEmail"
+          >
+          </SetList>
+        </div>
+      </div>
+    </div>
+    <vDialog
+      :title="email.title"
+      customClass="open-vip-dialog"
+      width="380px"
+      top="30vh"
+      center
+      :visible.sync="email.dialog"
+      @cancel="email.dialog = false"
+      @confirm="onConfirmEmail"
+      @close="onEmailDialogClose"
+      :disabled="emailConfirmDisabled"
+    >
+      <el-input v-model.trim="email.input" placeholder="请输入邮箱地址"></el-input>
+      <p class="error-tips" v-show="email.input && emailConfirmDisabled">邮箱格式不正确</p>
+    </vDialog>
+    <vDialog
+      title="我的订阅推送时间设置"
+      customClass="open-vip-dialog"
+      width="595px"
+      top="30vh"
+      center
+      :visible.sync="pushTime.dialog"
+      @cancel="pushTime.dialog = false"
+      @confirm="onConfirmPushTime"
+    >
+       <el-radio-group v-model="pushTime.checked" @input="onPushTimeRadioChange">
+        <el-radio :label="1">实时推送</el-radio>
+        <el-radio :label="2">每日推送</el-radio>
+        <el-radio :label="3">每周推送(周五)</el-radio>
+        <el-radio :label="4">每月推送(28日)</el-radio>
+      </el-radio-group>
+      <div class="push-tags" v-if="pushTime.checked > 1">
+        <span class="push-tags-label">推送时间:</span>
+        <div class="push-tags-value">
+          <el-tag
+            v-for="tag in sortTags"
+            :key="tag"
+            :closable="pushTime.checked === 2"
+            type="info"
+            @close="handleCloseTag(tag)"
+          >
+            {{tag}}
+          </el-tag>
+          <el-dropdown @command="handleAddTag" trigger="click" placement="bottom-start">
+            <span class="el-dropdown-link">
+              <el-button class="add-btn" v-if="canAddTag">+添加时间</el-button>
+            </span>
+            <el-dropdown-menu slot="dropdown" class="add-time-dropdown">
+              <el-dropdown-item v-for="time in hoursData" :key="time" :command="time">{{ time }}</el-dropdown-item>
+            </el-dropdown-menu>
+          </el-dropdown>
+        </div>
+      </div>
+    </vDialog>
+    <vDialog
+      title="开通超级订阅"
+      class="text-center"
+      custom-class="open-vip-dialog"
+      width="380px"
+      top="30vh"
+      center
+      :visible.sync="buy.dialog">
+      开通超级订阅可选择“实时推送”及时接收公告信息,或根据您的工作需要灵活设置推送时间。
+      <template #footer>
+        <button class="action-button confirm" style="margin: 0;" @click="toBuyVip">前往开通</button>
+        <button class="action-button cancel" style="margin: 0 48px 0 0;" @click="buy.dialog = false">取消</button>
+      </template>
+    </vDialog>
+    <vDialog
+      custom-class="follow-dialog"
+      width="200px"
+      top="30vh"
+      center
+      :show-close="true"
+      :visible.sync="follow.dialog"
+    >
+      <div class="wx-public-container">
+        <img :src="bind.wxCodeUrl" width="108" height="108" alt="微信公众号">
+        <p class="wx-public-tip">使用 <span class="hight-text">微信</span> 扫码关注,开启推送</p>
+      </div>
+      <span slot="footer" class="dialog-footer"></span>
+    </vDialog>
+  </div>
+</template>
+
+<script>
+import { Popover, Input, RadioGroup, Radio, Tag, Button, Dropdown, DropdownMenu, DropdownItem } from 'element-ui'
+import SetList from '@/components/push-setting/setList'
+import vDialog from '@/components/dialog/Dialog'
+import { getUserBindInfo, setUserBindInfo, getUserPushInfo, setUserPushInfo } from '@/api/modules/'
+import { mapGetters } from 'vuex'
+import { hoursData, pushFunctionData } from '@/assets/js/selector.js'
+export default {
+  name: 'pushSetting',
+  components: {
+    [Popover.name]: Popover,
+    [Input.name]: Input,
+    [RadioGroup.name]: RadioGroup,
+    [Radio.name]: Radio,
+    [Tag.name]: Tag,
+    [Button.name]: Button,
+    [Dropdown.name]: Dropdown,
+    [DropdownItem.name]: DropdownItem,
+    [DropdownMenu.name]: DropdownMenu,
+    SetList,
+    vDialog
+  },
+  data () {
+    return {
+      timer: null,
+      bind: {
+        email: '',
+        wx: false,
+        wxCodeUrl: ''
+      },
+      allListData: pushFunctionData,
+      usableList: [],
+      email: {
+        input: '',
+        dialog: false,
+        title: '',
+        clickType: ''
+      },
+      pushTime: {
+        dialog: false,
+        checked: 1,
+        tags: []
+      },
+      buy: {
+        dialog: false
+      },
+      follow: {
+        dialog: false
+      },
+      closable: false,
+      checkedTime: '',
+      hoursData: hoursData
+    }
+  },
+  computed: {
+    ...mapGetters('user', [
+      'free'
+    ]),
+    sortTags () {
+      return Array.from(new Set(this.pushTime.tags)).sort()
+    },
+    canAddTag () {
+      if (this.pushTime.checked === 2) {
+        return this.sortTags && this.sortTags.length < 10
+      } else {
+        return false
+      }
+    },
+    emailConfirmDisabled () {
+      return !(/\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/.test(this.email.input))
+    }
+  },
+  beforeDestroy () {
+    clearInterval(this.timer)
+  },
+  async created () {
+    await this.getUserBindInfoFn()
+    this.getUserPushInfoFn()
+  },
+  methods: {
+    // 获取当前绑定信息
+    async getUserBindInfoFn () {
+      const { data } = await getUserBindInfo({
+        serviceType: 'pc'
+      })
+      if (data) {
+        this.bind.email = data?.mail
+        this.bind.wx = data?.showWx
+        this.bind.wxCodeUrl = data?.imgUrl
+        if (data?.showWx) {
+          clearInterval(this.timer)
+          // 关注弹框显示时, 关注成功后提示toast
+          if (this.follow.dialog) {
+            setTimeout(() => {
+              this.follow.dialog = false
+              this.$toast('关注成功,可前往开启微信提醒啦')
+            }, 10)
+          }
+        } else {
+          clearInterval(this.timer)
+          // 未关注微信公众号 开启轮询
+          this.timer = setInterval(() => {
+            this.getUserBindInfoFn()
+          }, 3000)
+        }
+      }
+    },
+    // 获取当前推送设置
+    async getUserPushInfoFn () {
+      const { data } = await getUserPushInfo()
+      if (data) {
+        const arr = []
+        this.allListData.forEach(v => {
+          for (const key in data) {
+            if (v.type === key) {
+              for (const item in data[key]) {
+                v[item] = data[key][item]
+              }
+              if (!v.a_times) {
+                v.a_times = []
+              }
+              arr.push({
+                type: v.type,
+                name: v.name,
+                desc: v.desc,
+                showEdit: v.showEdit,
+                isWxShow: v.isWxShow,
+                mailPush: v.i_mailpush,
+                appPush: v.i_apppush,
+                wxPush: v.i_wxpush,
+                rateMode: v.i_ratemode,
+                times: v.a_times,
+                way: v.type === 'o_subset' ? this.getRateWay(v.i_ratemode, v.a_times) : v.a_times.toString()
+              })
+            }
+          }
+        })
+        this.usableList = arr
+        this.$forceUpdate()
+      }
+    },
+    // 推送设置修改
+    async setPushInfoFn (params, callback) {
+      const { error_code: code, error_msg: msg } = await setUserPushInfo(params)
+      callback && callback(code, msg)
+    },
+    onBindEmail (type) {
+      this.email.title = type === 'bind' ? '绑定邮箱' : '编辑邮箱'
+      this.email.dialog = true
+      this.email.input = this.bind.email ? this.bind.email : ''
+    },
+    async onConfirmEmail () {
+      if (!this.email.input) return
+      const { error_code: code, error_msg: msg } = await setUserBindInfo({
+        mail: this.email.input
+      })
+      if (code === 0) {
+        // 记录设置中点的哪一项邮箱提醒,设置完邮箱后打开所点的通知项
+        if (this.email.clickType) {
+          this.setPushInfoFn({
+            item: this.email.clickType,
+            setType: 'pushRoute',
+            pushType: 'i_mailpush',
+            pushValue: 1
+          }, (code, msg) => {
+            if (code === 0) {
+              this.getUserPushInfoFn()
+              this.$forceUpdate()
+              this.$toast('已开启', 1000)
+            } else {
+              this.$toast(msg)
+            }
+          })
+        }
+        this.email.dialog = false
+        await this.getUserBindInfoFn()
+      } else {
+        this.$toast(msg)
+      }
+    },
+    onEmailDialogClose () {
+      this.email.clickType = ''
+    },
+    onPushTimeEdit (data) {
+      if (this.free) {
+        this.buy.dialog = true
+        return
+      }
+      const { type, rateMode, times } = data
+      if (type === 'o_subset') {
+        this.pushTime.dialog = true
+        this.pushTime.checked = rateMode
+        this.pushTime.tags = times
+      }
+    },
+    // 推送时间修改
+    onConfirmPushTime () {
+      const params = {
+        item: 'o_subset',
+        setType: 'a_times',
+        ratemode: this.pushTime.checked,
+        times: this.sortTags
+      }
+      this.setPushInfoFn(params, (code, msg) => {
+        if (code === 0) {
+          this.getUserPushInfoFn()
+          // this.$forceUpdate()
+          this.pushTime.dialog = false
+        } else {
+          this.$toast(msg)
+        }
+      })
+    },
+    handleCloseTag (tag) {
+      if (this.pushTime.tags.length === 1) {
+        return this.$toast('请至少保留1个推送时间')
+      }
+      this.pushTime.tags.splice(this.pushTime.tags.indexOf(tag), 1)
+    },
+    handleAddTag (item) {
+      if (this.pushTime.tags.indexOf(item) > -1) {
+        return this.$toast('时间已存在')
+      }
+      this.pushTime.tags.push(item)
+    },
+    onPushTimeRadioChange (val) {
+      if (val > 1) {
+        this.pushTime.tags = ['09:00']
+      } else {
+        this.pushTime.tags = []
+      }
+    },
+    // 微信提醒switch冒泡事件
+    onSwitchWx (data) {
+      const { index, val, bind, type } = data
+      if (bind) {
+        this.setPushInfoFn({
+          item: type,
+          setType: 'pushRoute',
+          pushType: 'i_wxpush',
+          pushValue: val
+        }, (code, msg) => {
+          if (code === 0) {
+            this.$toast(val ? '已开启' : '已关闭', 1000)
+          } else {
+            this.$refs.funList[index].wxVal = Number(!val)
+            this.$toast(msg)
+          }
+        })
+      } else {
+        this.follow.dialog = true
+      }
+    },
+    // 邮箱提醒switch冒泡事件
+    onSwitchEmail (data) {
+      const { index, val, bind, type } = data
+      if (bind) {
+        this.setPushInfoFn({
+          item: type,
+          setType: 'pushRoute',
+          pushType: 'i_mailpush',
+          pushValue: val
+        }, (code, msg) => {
+          if (code === 0) {
+            this.$toast(val ? '已开启' : '已关闭', 1000)
+          } else {
+            this.$refs.funList[index].emailVal = Number(!val)
+            this.$toast(msg)
+          }
+        })
+      } else {
+        this.email.title = '绑定邮箱'
+        this.email.dialog = true
+        this.email.clickType = type
+      }
+    },
+    getRateWay (mode, times) {
+      switch (mode) {
+        case 1:
+          return '实时推送'
+        case 2:
+          return times ? `每日推送:${times.toString().replace(/,/g, '、')}` : '每日推送'
+        case 3:
+          return times ? `每周推送:${times.toString().replace(/,/g, '、')}` : '每周推送'
+        case 4:
+          return times ? `每月推送:${times.toString().replace(/,/g, '、')}` : '每月推送'
+      }
+    },
+    toBuyVip () {
+      location.href = '/swordfish/page_big_pc/free/svip/buy?type=buy'
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.push-setting{
+  width: 100%;
+  padding: 24px;
+  .title{
+    margin-bottom: 26px;
+    font-size: 24px;
+    line-height: 36px;
+    color: #1D1D1D;
+  }
+  .push-card {
+    margin-bottom: 24px;
+    background: #FFFFFF;
+    border-radius: 4px;
+  }
+  .channel{
+    padding: 12px 24px 48px;
+  }
+  .function{
+    padding: 12px 18px;
+  }
+  .card-title{
+    font-size: 16px;
+    line-height: 24px;
+    color: #1D1D1D;
+  }
+  .card-container{
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    margin-top: 12px;
+  }
+  .card-item{
+    min-width: 360px;
+    text-align: center;
+    .card-item-bg{
+      display: flex;
+      align-items: flex-end;
+      justify-content: center;
+      height: 160px;
+      background: linear-gradient(180deg, #F5F6F7 0%, rgba(245, 246, 247, 0) 100%);
+      border-radius: 8px;
+    }
+    .card-item-desc{
+      margin-top: 12px;
+      font-size: 14px;
+      line-height: 18px;
+      color: #AAAAAA;
+    }
+    .card-item-handle{
+      margin-top: 12px;
+      font-size: 14px;
+      line-height: 22px;
+      color: #1D1D1D;
+    }
+    .edit-text{
+      margin-left: 12px;
+      @extend .main-color;
+    }
+    .main-color{
+      color: $color_main;
+      cursor: pointer;
+    }
+  }
+  ::v-deep {
+    .custom-popover{
+      padding: 32px 18px;
+      border-radius: 8px;
+      border: 0;
+      .wx-public-container{
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+      }
+      .wx-public-tip{
+        margin-top: 10px;
+        font-size: 12px;
+        line-height: 18px;
+        white-space: nowrap;
+      }
+    }
+    .fun-head{
+      display: flex;
+      align-items: center;
+      height: 40px;
+      margin-top: 12px;
+      background: #F7F9FC;
+      border-radius: 4px;
+      p{
+        padding: 0 16px;
+        font-size: 14px;
+        color: #1D1D1D;
+      }
+      p:nth-child(1){
+        width: 44%;
+      }
+      p:nth-child(2){
+        width: 32%;
+      }
+      p:nth-child(3){
+        width: 26%;
+      }
+      .gray-color{
+        color: #686868;
+      }
+    }
+    .el-radio__label,
+    .el-radio__input.is-checked+.el-radio__label{
+      color: #1D1D1D;
+    }
+  }
+}
+</style>
+<style lang="scss">
+.hight-text{
+  color: $color_main;
+}
+.open-vip-dialog{
+  .el-dialog__header{
+    padding: 32px 32px 20px;
+  }
+  .el-dialog__body{
+    padding: 0 32px 0;
+    text-align: center;
+  }
+  .el-dialog__footer{
+    padding: 32px;
+  }
+  .error-tips{
+    margin-top: 4px;
+    padding: 0 4px;
+    color: #FF3A20;
+    font-size: 14px;
+    line-height: 22px;
+    text-align: left;
+  }
+  .dialog-footer{
+    flex-direction: row-reverse;
+    justify-content: center;
+    .action-button.cancel{
+      margin-left: 48px;
+      margin-right: 0;
+    }
+  }
+  .action-button{
+    width: 132px;
+    flex: unset;
+    font-size: 16px;
+  }
+  .push-tags{
+    display: flex;
+    justify-content: flex-start;
+    margin-top: 24px;
+    .el-tag{
+      margin-right: 14px;
+      margin-bottom: 8px;
+      background: #F7F9FC;
+      border-radius: 4px;
+      border: 0;
+      color: #1D1D1D;
+    }
+    .push-tags-label{
+      flex-shrink: 0;
+    }
+    .push-tags-value{
+      display: flex;
+      align-items: center;
+      flex-wrap: wrap;
+    }
+    .add-btn{
+      padding: 4px 16px;
+      margin-bottom: 8px;
+      color: $color_main;
+      border-color: $color_main;
+      font-size: 14px;
+      line-height: 22px;
+    }
+  }
+}
+.follow-dialog{
+  padding: 32px 0;
+  .el-dialog__body,
+  .el-dialog__header,
+  .el-dialog__footer{
+    padding: 0;
+  }
+  .el-dialog__headerbtn{
+    top: 8px;
+    right: 8px;
+  }
+  .wx-public-container{
+    text-align: center;
+  }
+  .wx-public-tip{
+    margin-top: 10px;
+    font-size: 12px;
+    line-height: 18px;
+    white-space: nowrap;
+  }
+}
+.add-time-dropdown{
+  width: 200px;
+  height: 240px;
+  overflow-y: auto;
+  &.el-popper[x-placement^=bottom]{
+    margin-top: 4px;
+  }
+  .el-dropdown-menu__item{
+    padding: 0 32px;
+  }
+}
+</style>