فهرست منبع

feat: 封装监控组合式函数及组件结合

zhangyuhan 1 سال پیش
والد
کامیت
81c849693a

+ 121 - 0
apps/bigmember_pc/src/composables/quick-monitor/component/QuickMonitor.vue

@@ -0,0 +1,121 @@
+<script setup>
+import commonDialog from '@/components/dialog/Dialog.vue'
+import CollectInfo from '@/components/collect-info/CollectInfo.vue'
+import MonitorPopover from '@/components/common/MonitorPopover.vue'
+import useQuickMonitorModel from '@/composables/quick-monitor'
+
+const props = defineProps({
+  type: String,
+  params: String
+})
+
+const {
+  // 基础展示信息
+  model,
+  doFetch,
+  doAddFollow,
+  TextConfig,
+  // popover 悬浮信息
+  monitorPopoverConfig,
+  doClickMonitorActions,
+  // dialog 提示弹窗
+  dialogConfig,
+  // 留资
+  collectElement
+} = useQuickMonitorModel({
+  type: props.type,
+  id: props.params
+})
+
+doFetch()
+</script>
+<template>
+  <div class="quick-monitor" v-if="model.canFollow">
+    <!--  icon + popover  -->
+    <div class="quick-monitor-popover">
+      <el-popover
+        popper-class="monitor-popover"
+        placement="bottom"
+        :append-to-body="false"
+        width="224"
+        trigger="hover"
+      >
+        <div
+          slot="reference"
+          class="flex-r-c center action-icon"
+          @click.stop="doAddFollow"
+        >
+          <i
+            class="icon iconfont"
+            :class="{
+              'icon-yijiankong': model.follow,
+              'icon-jiankong': !model.follow
+            }"
+          ></i>
+          <span>{{
+            model.follow ? TextConfig.follow : TextConfig.default
+          }}</span>
+        </div>
+        <monitor-popover
+          v-bind="monitorPopoverConfig"
+          @click="doClickMonitorActions"
+        ></monitor-popover>
+      </el-popover>
+    </div>
+    <!-- 提示弹窗 -->
+    <common-dialog
+      center
+      custom-class="monitor-class"
+      width="380px"
+      :visible="dialogConfig.show"
+      :title="dialogConfig.title"
+    >
+      <template #footer>
+        <button
+          v-for="(item, index) in dialogConfig.footerActions"
+          :key="index"
+          class="action-button"
+          :class="item.class"
+          @click="doClickMonitorActions(item.action || 'doCloseDialog')"
+        >
+          {{ item.label }}
+        </button>
+      </template>
+      {{ dialogConfig.content }}
+    </common-dialog>
+    <!-- 留资 -->
+    <collect-info ref="collectElement"></collect-info>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.quick-monitor-popover {
+  position: relative;
+}
+.action-icon {
+  .iconfont {
+    font-size: 18px;
+    color: #9b9ca3;
+    &.icon-yijiankong {
+      color: #ff9f40;
+    }
+    & + span {
+      margin-left: 2px;
+    }
+  }
+}
+::v-deep {
+  .monitor-class {
+    padding: 32px;
+    .el-dialog__header {
+      padding: 0;
+    }
+    .el-dialog__body {
+      padding: 20px 0 32px;
+    }
+    .el-dialog__footer {
+      padding: 0;
+    }
+  }
+}
+</style>

+ 11 - 0
apps/bigmember_pc/src/composables/quick-monitor/index.js

@@ -0,0 +1,11 @@
+import useProjectQuickMonitorModel from './use/porject'
+import useEntQuickMonitorModel from './use/ent'
+
+export default function useQuickMonitorModel(params) {
+  if (params.type === 'project') {
+    return useProjectQuickMonitorModel(params)
+  }
+  if (params.type === 'ent') {
+    return useEntQuickMonitorModel(params)
+  }
+}

+ 55 - 0
apps/bigmember_pc/src/composables/quick-monitor/use/base.js

@@ -0,0 +1,55 @@
+import { computed, reactive, ref, toRefs } from 'vue'
+import useQuickMonitor from '@jy/data-models/modules/quick-monitor/model'
+
+/**
+ * 提供监控提示弹窗 双向绑定 ref
+ * @param dialogDataMap - 文案等配置项
+ */
+export function useMonitorTipDialog(dialogDataMap) {
+  const dialogShow = ref(false)
+  const dialogShowType = ref('monitor-success')
+  const dialogParams = ref({})
+  const dialogConfig = computed(() =>
+    Object.assign(
+      {
+        type: dialogShowType.value,
+        params: dialogParams.value,
+        show: dialogShow.value
+      },
+      dialogDataMap[dialogShowType.value]
+    )
+  )
+
+  function doOpenDialog(type, params = {}) {
+    dialogShowType.value = type
+    dialogShow.value = true
+    dialogParams.value = params
+  }
+  function doCloseDialog() {
+    dialogShow.value = false
+  }
+
+  return {
+    dialogConfig,
+    doOpenDialog,
+    doCloseDialog
+  }
+}
+
+/**
+ * 转换监控 @data-models/quick-monitor 数据模型为双向绑定 ref
+ * @param type
+ * @param id
+ */
+export function useMonitorModel({ type, id }) {
+  const useMonitor = useQuickMonitor({
+    type: type,
+    params: {
+      id: id
+    }
+  })
+  const { doFetch, doChange } = useMonitor
+  const { model } = toRefs(reactive(useMonitor))
+
+  return { model, doChange, doFetch }
+}

+ 230 - 0
apps/bigmember_pc/src/composables/quick-monitor/use/ent.js

@@ -0,0 +1,230 @@
+import { computed, ref, getCurrentInstance } from 'vue'
+import { useStore } from '@/store'
+import { useMonitorModel, useMonitorTipDialog } from './base'
+
+/**
+ * 文案项目配置
+ */
+const TextConfig = {
+  default: '监控',
+  follow: '已监控'
+}
+/**
+ * 弹窗相关配置表
+ */
+const DialogDataMap = {
+  'success-monitor': {
+    title: '监控成功',
+    content:
+      '您可前往“工作台-商机-项目进度监控”查看项目最新招标/采购进度。为保证您能及时获取新增监控信息推送,请前往开启推送提醒。',
+    footerActions: [
+      {
+        label: '暂不开启',
+        class: 'cancel'
+      },
+      {
+        label: '去开启',
+        class: 'confirm',
+        action: 'doOpenPushSetting'
+      }
+    ]
+  },
+  'max-monitor': {
+    title: '监控项目个数已达上限',
+    content: '您最多可监控$1个项目,可联系客服,申请监控更多项目',
+    footerActions: [
+      {
+        label: '我再想想',
+        class: 'cancel'
+      },
+      {
+        label: '联系客服',
+        class: 'confirm',
+        action: 'doOpenCustomer'
+      }
+    ]
+  },
+  'apply-monitor': {
+    title: '申请监控更多项目',
+    content: '您可联系客服,申请升级产品套餐,监控更多项目',
+    footerActions: [
+      {
+        label: '我再想想',
+        class: 'cancel'
+      },
+      {
+        label: '联系客服',
+        class: 'confirm',
+        action: 'doOpenCustomer'
+      }
+    ]
+  },
+  'cancel-monitor': {
+    title: '确定不再监控?',
+    content: '取消监控,将错过项目最新动态推送',
+    footerActions: [
+      {
+        label: '确认取消',
+        class: 'cancel',
+        action: 'doRemoveFollow'
+      },
+      {
+        label: '我再想想',
+        class: 'confirm'
+      }
+    ]
+  },
+  'success-toast': '监控成功,您可前往“工作台-商机-项目进度监控”查看'
+}
+
+/**
+ * 弹窗相关事件 Emit
+ */
+// 打开推送提醒设置
+function doOpenPushSetting() {}
+
+function useEntQuickMonitorModel({ type, id }) {
+  const that = getCurrentInstance().proxy
+  const collectElement = ref(null)
+  const { dialogConfig, doOpenDialog, doCloseDialog } =
+    useMonitorTipDialog(DialogDataMap)
+  const HasPowerBigmemberOrEnt = computed(() => {
+    const store = useStore()
+    return store.getters['user/entniche'] || store.getters['user/bigmember']
+  })
+  const loading = ref(false)
+  const { model, doChange, doFetch } = useMonitorModel({ type, id })
+  const monitorPopoverConfig = computed(() => {
+    return {
+      showTip: !model.value.follow,
+      showMore: model.value.follow,
+      showList: true,
+      showCancel: model.value.follow,
+      alreadyNum: model.value.expands.used,
+      remainNum: model.value.expands.surplus,
+      textType: type
+    }
+  })
+
+  // 打开留资弹窗
+  function doOpenCollectDialog(key) {
+    collectElement.value?.noCallApiFn(key || 'pc_article_project_more', false)
+  }
+
+  // 联系客服
+  function doOpenCustomer() {
+    that?.contactCustomer(that)
+  }
+
+  /**
+   * 监控操作业务流程
+   * 0. 前置权益判断
+   *  0.1 判断是否非大会员、非商机管理用户
+   *    > 否,留资弹窗
+   * 1. 监控成功
+   *  1.1 判断是否开启推送提醒
+   *    > 是,提醒开启推送提醒 success-monitor
+   *    > 否,toast 提醒监控成功 success-toast
+   * 2. 监控失败
+   *  2.1 超出可监控项目个数
+   *    2.1.1 判断是否非大会员、非商机管理用户
+   *      > 是,弹窗提醒 max-monitor
+   *      > 否,留资弹窗
+   *  2.2 其他错误,toast 提醒
+   * @return {Promise<void>}
+   */
+  async function doAddFollow() {
+    if (loading.value) return
+    loading.value = true
+    // 业务流程
+    if (!model.value.follow) {
+      await doChange().then((res) => {
+        if (res.success) {
+          // 判断是否开启推送提醒
+          if (res.data?.msg_open) {
+            doOpenDialog('success-monitor')
+          } else {
+            that.$toast(DialogDataMap['success-toast'])
+          }
+        } else {
+          // 判断是否超出可监控项目个数
+          if (res.data?.limit_status) {
+            if (HasPowerBigmemberOrEnt.value) {
+              doOpenDialog('max-monitor', { count: res.data?.limit_status })
+            } else {
+              doOpenCollectDialog('pc_article_project_limit')
+            }
+          }
+          that.$toast(res.msg)
+        }
+      })
+    }
+    loading.value = false
+  }
+
+  /**
+   * 统一处理 dialog, popover emit 事件
+   * @param {string} type
+   *  // popover 事务
+   *  - more 查看监控动态
+   *  - list 查看监控列表
+   *  - apply 申请监控更多
+   *  - cancel 取消监控确认弹窗
+   *  // dialog 事务
+   *  - doCloseDialog 关闭弹窗
+   *  - doRemoveFollow 提交取消监控事务
+   *  - doOpenCustomer 联系客服
+   *  - doOpenPushSetting 打开推送提醒设置
+   */
+  function doClickMonitorActions(type) {
+    switch (type) {
+      case 'doCloseDialog':
+        doCloseDialog()
+        break
+      case 'doOpenCustomer':
+        doOpenCustomer()
+        break
+      case 'doOpenPushSetting':
+        doOpenPushSetting()
+        break
+      case 'doRemoveFollow':
+        doChange().then((res) => {
+          that.$toast(res.msg)
+        })
+        break
+      case 'cancel':
+        doOpenDialog('cancel-monitor')
+        break
+      case 'apply':
+        if (HasPowerBigmemberOrEnt.value) {
+          doOpenDialog('apply-monitor')
+        } else {
+          doOpenCollectDialog('pc_article_project_more')
+        }
+        break
+      case 'more':
+        break
+      case 'list':
+        break
+      default:
+        break
+    }
+  }
+
+  return {
+    // 基础展示信息
+    model,
+    doFetch,
+    doAddFollow,
+    TextConfig,
+    // popover 悬浮信息
+    monitorPopoverConfig,
+    doClickMonitorActions,
+    // dialog 提示弹窗
+    dialogConfig,
+    // 留资
+    collectElement
+  }
+}
+
+export default useEntQuickMonitorModel

+ 231 - 0
apps/bigmember_pc/src/composables/quick-monitor/use/porject.js

@@ -0,0 +1,231 @@
+import { computed, ref, getCurrentInstance } from 'vue'
+import { useStore } from '@/store'
+import { useMonitorModel, useMonitorTipDialog } from './base'
+
+/**
+ * 文案项目配置
+ */
+const TextConfig = {
+  default: '监控',
+  follow: '已监控'
+}
+/**
+ * 弹窗相关配置表
+ */
+const DialogDataMap = {
+  'success-monitor': {
+    title: '监控成功',
+    content:
+      '您可前往“工作台-商机-项目进度监控”查看项目最新招标/采购进度。为保证您能及时获取新增监控信息推送,请前往开启推送提醒。',
+    footerActions: [
+      {
+        label: '暂不开启',
+        class: 'cancel'
+      },
+      {
+        label: '去开启',
+        class: 'confirm',
+        action: 'doOpenPushSetting'
+      }
+    ]
+  },
+  'max-monitor': {
+    title: '监控项目个数已达上限',
+    content: '您最多可监控$1个项目,可联系客服,申请监控更多项目',
+    footerActions: [
+      {
+        label: '我再想想',
+        class: 'cancel'
+      },
+      {
+        label: '联系客服',
+        class: 'confirm',
+        action: 'doOpenCustomer'
+      }
+    ]
+  },
+  'apply-monitor': {
+    title: '申请监控更多项目',
+    content: '您可联系客服,申请升级产品套餐,监控更多项目',
+    footerActions: [
+      {
+        label: '我再想想',
+        class: 'cancel'
+      },
+      {
+        label: '联系客服',
+        class: 'confirm',
+        action: 'doOpenCustomer'
+      }
+    ]
+  },
+  'cancel-monitor': {
+    title: '确定不再监控?',
+    content: '取消监控,将错过项目最新动态推送',
+    footerActions: [
+      {
+        label: '确认取消',
+        class: 'cancel',
+        action: 'doRemoveFollow'
+      },
+      {
+        label: '我再想想',
+        class: 'confirm'
+      }
+    ]
+  },
+  'success-toast': '监控成功,您可前往“工作台-商机-项目进度监控”查看'
+}
+
+/**
+ * 弹窗相关事件 Emit
+ */
+// 打开推送提醒设置
+function doOpenPushSetting() {}
+
+function useProjectQuickMonitorModel({ type, id }) {
+  const that = getCurrentInstance().proxy
+  const collectElement = ref(null)
+  const { dialogConfig, doOpenDialog, doCloseDialog } =
+    useMonitorTipDialog(DialogDataMap)
+  const HasPowerBigmemberOrEnt = computed(() => {
+    const store = useStore()
+    return store.getters['user/entniche'] || store.getters['user/bigmember']
+  })
+  const loading = ref(false)
+  const { model, doChange, doFetch } = useMonitorModel({ type, id })
+  const monitorPopoverConfig = computed(() => {
+    return {
+      showTip: !model.value.follow,
+      showMore: model.value.follow,
+      showList: true,
+      showCancel: model.value.follow,
+      alreadyNum: model.value.expands.used,
+      remainNum: model.value.expands.surplus,
+      textType: type
+    }
+  })
+
+  // 打开留资弹窗
+  function doOpenCollectDialog(key) {
+    collectElement.value?.noCallApiFn(key || 'pc_article_project_more', false)
+  }
+
+  // 联系客服
+  function doOpenCustomer() {
+    that?.contactCustomer(that)
+  }
+
+  /**
+   * 监控操作业务流程
+   * 0. 前置权益判断
+   *  0.1 判断是否非大会员、非商机管理用户
+   *    > 否,留资弹窗
+   * 1. 监控成功
+   *  1.1 判断是否开启推送提醒
+   *    > 是,提醒开启推送提醒 success-monitor
+   *    > 否,toast 提醒监控成功 success-toast
+   * 2. 监控失败
+   *  2.1 超出可监控项目个数
+   *    2.1.1 判断是否非大会员、非商机管理用户
+   *      > 是,弹窗提醒 max-monitor
+   *      > 否,留资弹窗
+   *  2.2 其他错误,toast 提醒
+   * @return {Promise<void>}
+   */
+  async function doAddFollow() {
+    if (loading.value) return
+    loading.value = true
+    // 业务流程
+    if (!model.value.follow) {
+      await doChange().then((res) => {
+        if (res.success) {
+          // 判断是否开启推送提醒
+          if (!res.data?.msg_open) {
+            doOpenDialog('success-monitor')
+          } else {
+            that.$toast(DialogDataMap['success-toast'])
+          }
+        } else {
+          // 判断是否超出可监控项目个数
+          if (res.data?.limit_status) {
+            if (HasPowerBigmemberOrEnt.value) {
+              doOpenDialog('max-monitor', { count: res.data?.limit_status })
+            } else {
+              doOpenCollectDialog('pc_article_project_limit')
+            }
+          }
+          that.$toast(res.msg)
+        }
+      })
+    }
+    loading.value = false
+  }
+
+  /**
+   * 统一处理 dialog, popover emit 事件
+   * @param {string} type
+   *  // popover 事务
+   *  - more 查看监控动态
+   *  - list 查看监控列表
+   *  - apply 申请监控更多
+   *  - cancel 取消监控确认弹窗
+   *  // dialog 事务
+   *  - doCloseDialog 关闭弹窗
+   *  - doRemoveFollow 提交取消监控事务
+   *  - doOpenCustomer 联系客服
+   *  - doOpenPushSetting 打开推送提醒设置
+   */
+  function doClickMonitorActions(type) {
+    switch (type) {
+      case 'doCloseDialog':
+        doCloseDialog()
+        break
+      case 'doOpenCustomer':
+        doOpenCustomer()
+        break
+      case 'doOpenPushSetting':
+        doOpenPushSetting()
+        break
+      case 'doRemoveFollow':
+        doChange().then((res) => {
+          that.$toast(res.msg)
+          doCloseDialog()
+        })
+        break
+      case 'cancel':
+        doOpenDialog('cancel-monitor')
+        break
+      case 'apply':
+        if (HasPowerBigmemberOrEnt.value) {
+          doOpenDialog('apply-monitor')
+        } else {
+          doOpenCollectDialog('pc_article_project_more')
+        }
+        break
+      case 'more':
+        break
+      case 'list':
+        break
+      default:
+        break
+    }
+  }
+
+  return {
+    // 基础展示信息
+    model,
+    doFetch,
+    doAddFollow,
+    TextConfig,
+    // popover 悬浮信息
+    monitorPopoverConfig,
+    doClickMonitorActions,
+    // dialog 提示弹窗
+    dialogConfig,
+    // 留资
+    collectElement
+  }
+}
+
+export default useProjectQuickMonitorModel

+ 1 - 1
apps/bigmember_pc/src/views/article-content/components/ContentHeader.vue

@@ -1,7 +1,7 @@
 <script setup>
 import shareBox from '@/components/shareBox/index.vue'
 import powerPerson from '@/components/subscribe-manager/powerPerson.vue'
-import QuickMonitor from '@/views/article-content/components/QuickMonitor.vue'
+import QuickMonitor from '@/composables/quick-monitor/component/QuickMonitor.vue'
 import { ContentModel } from '@/views/article-content/composables/useContentStore'
 import { computed, getCurrentInstance, onMounted, ref } from 'vue'
 import { useRoute } from 'vue-router/composables'