Преглед на файлове

feat: 新增附件下载逻辑

zhangyuhan преди 1 година
родител
ревизия
501231d809

+ 29 - 0
apps/bigmember_pc/src/api/modules/detail.js

@@ -56,3 +56,32 @@ export function getArticleOriginalText(data) {
     data
   })
 }
+
+// 获取标讯详情页附件信息
+export function ajaxGetAttachmentList(data) {
+  return request({
+    url: '/bigmember/attachment/get',
+    method: 'post',
+    noToast: true,
+    data: qs.stringify(data)
+  })
+}
+
+// 获取各种资源包余额信息
+export function getResourcePackAccount(data) {
+  return request({
+    url: '/jypay/resourcePack/account',
+    method: 'post',
+    data: qs.stringify(data)
+  })
+}
+
+// 资源包兑换接口
+export function useResourcePack(data) {
+  return request({
+    url: '/jypay/resourcePack/consumePack',
+    method: 'post',
+    noToast: true,
+    data: qs.stringify(data)
+  })
+}

+ 4 - 0
apps/bigmember_pc/src/assets/style/_variables.scss

@@ -6,6 +6,10 @@ $footerHeight: 364px;
 
 $color_main: #2cb7ca;
 
+// Background
+// 透明背景色使用时,需要配合白色背景使用
+$color_main_background: rgb($color_main,.1);
+
 $bg-retrieve: #010c28;
 $bg-button--default: linear-gradient(84deg, #af9552 0%, #efda98 100%);
 $bg-card--default: linear-gradient(#031242 0%, #010e36 100%);

+ 12 - 0
apps/bigmember_pc/src/assets/style/reset-ele.scss

@@ -111,6 +111,18 @@
       background: #2cb7ca;
     }
   }
+
+  .custom-cancel-btn,
+  .custom-cancel-btn:hover,
+  .custom-cancel-btn:focus{
+    width: 132px;
+    height: 34px;
+    background-color: #fff;
+    border: 1px solid #DCDFE6;
+    color: #686868;
+    font-size: 16px;
+  }
+
   .el-message-box__message,
   .message-text {
     font-size: 14px;

+ 441 - 0
apps/bigmember_pc/src/composables/attachment-download/component/AttachmentDownload.vue

@@ -0,0 +1,441 @@
+<template>
+  <section class="attachment-download-container" v-if="renderAttachList.length">
+    <div class="others-header flex flex-(items-center justify-between)">
+      <div class="content-file-attachment-left flex flex-items-center">
+        <span class="left-icon flex flex-items-center">
+          <span class="j-icon icon-data-download"></span>
+          <span class="file-attachment-text text-nowrap">附件下载</span>
+        </span>
+        <div class="right-content flex flex-items-center">
+          <!-- 免费用户,无体验次数(没体验过) -->
+          <template v-if="isFree && freeFileNum === 0">
+            <span class="attachment-tag text-nowrap">
+              <span class="attachment-tag-text">
+                免费用户享有{{ freeFileNum || 1 }}次附件下载权益
+              </span>
+            </span>
+          </template>
+          <!-- 免费用户,无体验次数(体验过) -->
+          <template v-else-if="isFree && freeFileNum < 0">
+            <span class="attachment-tag text-nowrap">
+              <span class="attachment-tag-text">下载更多附件</span>
+              <button class="open-vip-btn" @click="toBuySvip">
+                开通超级订阅
+              </button>
+            </span>
+          </template>
+          <!-- 新超级订阅,并且不是大会员(或者是大会员没有附件下载权限) -->
+          <template v-else-if="isNewSuper && !memberHasAttachPower">
+            <span class="attachment-tag text-nowrap">
+              <span class="attachment-tag-text">本月剩余:{{ fileNum }}个</span>
+            </span>
+            <i class="iconfont icon-help" @click="fileDownloadHelp"></i>
+          </template>
+        </div>
+      </div>
+      <div class="content-file-attachment-actions">
+        <span
+          class="action-button"
+          @click="chargeFilePack"
+          v-if="isNewSuper && !memberHasAttachPower"
+        >
+          立即充值
+        </span>
+      </div>
+    </div>
+    <div class="file-attachment-list">
+      <div
+        class="file-attachment-item highlight-text underline clickable"
+        v-for="(attach, index) in renderAttachList"
+        @click="startDownloadFile(attach)"
+        :key="index"
+      >
+        {{ attach.name }}
+      </div>
+    </div>
+  </section>
+</template>
+
+<script>
+import { mapState, mapGetters } from 'vuex'
+import { useGetContentAttachment } from '@/composables/attachment-download/'
+
+export default {
+  name: 'AttachmentDownload',
+  props: {
+    id: {
+      type: String,
+      required: true,
+      default: ''
+    },
+    type: {
+      type: String,
+      default: ''
+    },
+    title: {
+      type: String,
+      required: true,
+      default: ''
+    },
+    attachmentList: {
+      type: Array,
+      default() {
+        return [
+          // {
+          //   fileName: '附件1.pdf',
+          //   fileSize: '1.9 M',
+          //   fileType: 'pdf'
+          // },
+          // {
+          //   fileName: '附件2.pdf',
+          //   fileSize: '129 KB',
+          //   fileType: 'pdf'
+          // }
+        ]
+      }
+    }
+  },
+  data() {
+    return {
+      loading: false,
+      attachment: {
+        fileUrl: '', // 当前附件真实url
+        file: {}, // 当前需要下载的附件信息
+        downloaded: false
+      },
+      resourcePack: {
+        exchangeNum: 0,
+        freeNum: 0,
+        grantNum: 0,
+        name: '附件下载包',
+        number: 0,
+        purchaseNum: 0,
+        resourceType: '附件下载包',
+        thirtyNum: 0
+      }
+    }
+  },
+  computed: {
+    ...mapGetters('user', [
+      'isFree',
+      'isSuper',
+      'isMember',
+      'bigMemberPower',
+      'isBusiness'
+    ]),
+    ...mapState({
+      power: (state) => state.user.info
+    }),
+    // 免费用户免费体验次数
+    freeFileNum() {
+      if (this.resourcePack.number > 0) {
+        return this.resourcePack.number
+      } else {
+        if (this.attachment.downloaded) {
+          return -1
+        } else {
+          return this.power?.freeFile
+        }
+      }
+    },
+    fileNum() {
+      return this.power?.fileNum || 0
+    },
+    isNewSuper() {
+      return this.power.viper && this.isSuper
+    },
+    memberHasAttachPower() {
+      return this.bigMemberPower.indexOf(3) !== -1
+    },
+    renderAttachList() {
+      return this.attachmentList.map((a) => {
+        let size = a.fileSize
+        return {
+          name: a.fileName,
+          size: size,
+          type: a.fileType
+        }
+      })
+    }
+  },
+  created() {
+    this.getInfo()
+  },
+  methods: {
+    replaceSpace(n) {
+      return n.trim().replace(/\s+/g, '')
+    },
+    async getInfo() {
+      const { attachment } = useGetContentAttachment({ id: this.id })
+      this.attachmentInstance = attachment
+      await this.attachmentInstance.getResourcePackAccount()
+      this.resourcePack = this.attachmentInstance.resourcePack
+    },
+    async refreshResourcePackCount() {
+      if (!this.attachmentInstance) {
+        return this.getInfo()
+      }
+      await this.attachmentInstance.getResourcePackAccount()
+      this.resourcePack = this.attachmentInstance.resourcePack
+    },
+    showDialog(conf = {}) {
+      const defaultConf = {
+        title: '',
+        message: '',
+        customClass: 'custom-message-box',
+        confirmButtonText: '我知道了',
+        confirmButtonClass: 'custom-confirm-btn',
+        cancelButtonClass: 'custom-cancel-btn',
+        showClose: false,
+        showCancelButton: false,
+        closeOnClickModal: false,
+        center: true
+      }
+      Object.assign(defaultConf, conf)
+      return this.$confirm(defaultConf.message, defaultConf.title, defaultConf)
+    },
+    fileDownloadHelp() {
+      this.$dialog.alert({
+        message:
+          '点击附件即为下载,系统会扣除当月附件下载个数;每月1号上月余额清零重新计算,请合理使用。',
+        className: 'j-confirm-dialog',
+        confirmButtonText: '我知道了'
+      })
+    },
+    async startDownloadFile(file) {
+      if (this.isFree) {
+        // 免费用户
+        // 判断有无体验过 0:未体验过
+        if (this.freeFileNum === 0) {
+          // TODO 判断有无留过资 且未体验过 - 去留资 source: 'article_attach_freeuser'
+          this.$emit('doOpenCollect', {
+            source: 'article_attach_freeuser',
+            reload: true
+          })
+        } else if (this.freeFileNum < 0 && this.resourcePack.number <= 0) {
+          // 免费用户 体验过 下载次数为-1 弹框提醒跳至超级订阅购买页
+          // 并且剑鱼币兑换的附件下载权益没有余额
+          return this.showDialog({
+            title: '开通超级订阅',
+            message:
+              '您的免费【附件下载】次数已使用完,暂无免费查看权限。如需查看更多,请开通超级订阅获取更多权限。',
+            showCancelButton: true,
+            confirmButtonText: '去开通'
+          })
+            .then(() => {
+              this.toBuySvip()
+            })
+            .catch(() => {})
+        } else {
+          // P317版本改为免费用户只要有下载次数,均可正常下载
+          this.downloadFile(file)
+          this.attachment.downloaded = true
+        }
+      } else {
+        // 付费用户
+        // 大会员用户 有下载个数
+        if (this.memberHasAttachPower) {
+          return this.downloadFile(file)
+        }
+        // 超级订阅用户
+        if (this.isSuper) {
+          // 新超级订阅用户
+          if (this.isNewSuper) {
+            // 是否用完弹窗放到请求之后,根据请求返回值进行判断
+            return this.downloadFile(file)
+            // if (this.fileNum > 0) {
+            //   this.downloadFile(file)
+            // } else {
+            //   // 次数用完
+            //   return this.showDialog({
+            //     message:
+            //       '您本月附件下载机会已消耗完毕,如需下载更多附件,请前往充值。',
+            //     showCancelButton: true,
+            //     confirmButtonText: '立即充值'
+            //   })
+            //     .then(() => {
+            //       // this.concatKf()
+            //       this.chargeFilePack()
+            //     })
+            //     .catch(() => {})
+            // }
+          } else {
+            // 老超级订阅用户 提醒升级
+            return this.showDialog({
+              title: '升级超级订阅',
+              message: '对不起,暂无权限,您可升级超级订阅解锁附件下载',
+              showCancelButton: true,
+              confirmButtonText: '前往升级'
+            })
+              .then(() => {
+                this.toUpgradeSvip()
+              })
+              .catch(() => {})
+          }
+        }
+
+        // 商机管理只要有个数就能下载
+        if (this.isBusiness && this.resourcePack.number > 0) {
+          return this.downloadFile(file)
+        }
+
+        // 大会员自定义版本没有下载权限 或 非超级订阅的商机管理用户 (弹框提醒联系客服)
+        const isMemberButNoPower = this.isMember && !this.memberHasAttachPower
+        const noAttachmentDownloadPower = isMemberButNoPower && !this.isNewSuper
+        if (noAttachmentDownloadPower || (!this.isSuper && this.isBusiness)) {
+          // 老超级订阅用户 提醒升级
+          return this.showDialog({
+            message:
+              '您未购买此服务,如需使用请联系您的客户经理或客服升级套餐,谢谢!',
+            confirmButtonText: '我知道了'
+          })
+            .then(() => {})
+            .catch(() => {})
+        }
+      }
+    },
+    async downloadFile(file) {
+      this.attachment.file = file
+      // downUrl: 原始url
+      // fileUrl: 下载地址
+      const { downUrl, fileUrl } = await this.getAttachmentInfo(file)
+      this.refreshResourcePackCount()
+
+      if (downUrl && fileUrl) {
+        location.href = fileUrl
+      } else {
+        console.log('获取附件fid失败')
+      }
+    },
+    async getAttachmentInfo(file) {
+      this.loading = true
+      if (!this.loading) return
+      const params = {
+        id: this.id, // 附件详情页id
+        fileName: file.name, // 附件名称
+        infoType: this.type === 'issued' ? 'S' : '', // 信息类型:默认为空; 供应信息:S
+        productName: '附件下载包',
+        platform: 'PC', // 平台:PC;APP;WX
+        title: this.title // 附件详情页标题附件详情页标题
+      }
+      try {
+        const { r: data, m: msg } =
+          await this.attachmentInstance.useResourcePack(params)
+        // 各种余额不足提示
+        if (data) {
+          if (data.code && data.code < 0) {
+            if (this.isFree) {
+              this.showDialog({
+                title: '开通超级订阅',
+                message:
+                  '您的免费【附件下载】次数已使用完,暂无免费查看权限。如需查看更多,请开通超级订阅获取更多权限。',
+                showCancelButton: true,
+                confirmButtonText: '去开通'
+              })
+                .then(() => {
+                  this.toBuySvip()
+                })
+                .catch(() => {})
+            } else if (this.isSuper) {
+              this.showDialog({
+                title: '开通超级订阅',
+                message:
+                  '您本月附件下载机会已消耗完毕,如需下载更多附件,请前往充值。',
+                showCancelButton: true,
+                confirmButtonText: '立即充值'
+              })
+                .then(() => {
+                  this.chargeFilePack()
+                })
+                .catch(() => {})
+            } else {
+              this.$toast(msg || '获取附件地址失败')
+            }
+          } else if (!msg && data.downUrl) {
+            const downUrl = data.downUrl
+            const fileUrl = downUrl
+              ? `${downUrl}?response-content-type=application/octet-stream`
+              : ''
+            return {
+              ...data,
+              fileUrl // 真实下载地址
+            }
+          } else {
+            this.$toast(msg || '获取附件地址失败')
+          }
+        } else {
+          this.$toast(msg || '获取附件地址失败')
+        }
+      } catch (error) {
+        console.log(error)
+      } finally {
+        this.loading = false
+      }
+    },
+    toBuySvip() {
+      window.open('/swordfish/page_big_pc/free/svip/buy', '_blank')
+    },
+    chargeFilePack() {
+      window.open('/swordfish/page_big_pc/free/filePack/buy', '_blank')
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.attachment-download-container {
+  margin-top: 40px;
+  margin-bottom: 70px;
+}
+.file-attachment-text {
+  margin-right: 12px;
+  font-size: 16px;
+  line-height: 24px;
+}
+.attachment-tag {
+  margin: 0 8px;
+  padding: 2px 0;
+  font-size: 12px;
+  line-height: 18px;
+  color: $color-main;
+  background: $color_main_background;
+  border-radius: 10px;
+  &-text {
+    padding: 0 8px;
+    color: $color-main;
+  }
+}
+.action-button {
+  flex-shrink: 0;
+  min-width: 64px;
+  padding: 3px 8px;
+  font-size: 12px;
+  line-height: 18px;
+  border-radius: 8px;
+  color: #fff;
+  background-color: $color-main;
+}
+.file-attachment-list {
+  margin-top: 16px;
+  font-size: 15px;
+  line-height: 22px;
+  .file-attachment-item {
+    display: inline-block;
+    cursor: pointer;
+    margin-bottom: 16px;
+  }
+}
+
+.right-content {
+  .iconfont {
+    color: $color-main;
+  }
+}
+
+.open-vip-btn {
+  color: #fff;
+  padding: 0 8px;
+  border-radius: inherit;
+  background-color: $color-main;
+}
+</style>

+ 87 - 0
apps/bigmember_pc/src/composables/attachment-download/index.js

@@ -0,0 +1,87 @@
+import {
+  ajaxGetAttachmentList,
+  getResourcePackAccount,
+  useResourcePack
+} from '@/api/modules/detail'
+
+export class Attachment {
+  constructor(name, size, downUrl, originUrl) {
+    this.name = name || ''
+    this.size = size || ''
+    this.downUrl = downUrl || ''
+    this.originUrl = originUrl || ''
+  }
+}
+
+class AttachmentList {
+  constructor({ id }) {
+    // 标讯id,必传
+    this.id = id
+    if (!id) {
+      return console.error('id必传')
+    }
+    // 附件列表
+    this.attachmentList = []
+    this.resourcePack = null
+  }
+
+  replaceSpace(n) {
+    return n.trim().replace(/\s+/g, '')
+  }
+
+  async getAttachList() {
+    const id = this.id
+    try {
+      const {
+        error_code: code,
+        error_msg: msg,
+        data
+      } = await ajaxGetAttachmentList({ infoId: id })
+      if (code === 0 && data) {
+        if (Array.isArray(data.attachment) && data.attachment.length > 0) {
+          this.attachmentList = data.attachment.map((a) => {
+            let size = a.size
+            return new Attachment(a.filename, size, a.downurl, a.org_url)
+          })
+          await this.getResourcePackAccount()
+        }
+      } else {
+        console.log(msg)
+      }
+    } catch (error) {
+      console.log(error)
+    }
+  }
+
+  async getResourcePackAccount() {
+    const params = {
+      product: 'attachmentDownPack'
+    }
+    try {
+      const { data } = await getResourcePackAccount(params)
+      if (data && Array.isArray(data.data)) {
+        this.resourcePack = data.data[0]
+        return this.resourcePack
+      }
+    } catch (error) {
+      console.log(error)
+    }
+  }
+
+  async useResourcePack({ platform, fileName, id, title }) {
+    const params = {
+      productName: '附件下载包',
+      platform: platform.toLowerCase(),
+      fileName,
+      id,
+      title
+    }
+    return useResourcePack(params)
+  }
+}
+
+export function useGetContentAttachment({ id }) {
+  return {
+    attachment: new AttachmentList({ id })
+  }
+}

+ 18 - 1
apps/bigmember_pc/src/store/user.js

@@ -467,6 +467,23 @@ export default {
     // 个人版
     isPersonalVersion: (state) => state.userIdentity.positionType === 0,
     // 企业版
-    isEntVersion: (state) => state.userIdentity.positionType === 1
+    isEntVersion: (state) => state.userIdentity.positionType === 1,
+    // 兼容用法
+    isFree: (_, getters) => getters.free,
+    isSuper: (_, getters) => getters.svip,
+    isMember: (_, getters) => getters.bigmember,
+    isBusiness: (_, getters) => {
+      const { entniche, bigmember } = getters
+      const vip = entniche || bigmember
+      return !vip
+    },
+    bigMemberPower: (state) => {
+      const { power } = state
+      if (power && power.power) {
+        return power.power
+      } else {
+        return []
+      }
+    }
   }
 }