QuickMonitor.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. <template>
  2. <van-popover
  3. v-model="showPopover"
  4. v-if="model.canFollow"
  5. trigger="click"
  6. :placement="placement"
  7. :offset="calcOffset"
  8. >
  9. <FollowPopoverContentCard
  10. :used="model.expands?.used"
  11. :surplus="model.expands?.surplus"
  12. @toTimeline="toProjectDetail"
  13. @toMyFollow="toMonitorList"
  14. @applyMore="applyMoreMonitor"
  15. @cancelFollow="cancelMonitor"
  16. />
  17. <template #reference>
  18. <TabActionItem
  19. showText
  20. :direction="direction"
  21. class="action-monitor"
  22. @click.native.stop="changePopoverState"
  23. >
  24. <AppIcon
  25. slot="icon"
  26. :name="model.follow ? 'yijiankong' : 'jiankong'"
  27. svg
  28. size="20"
  29. ></AppIcon>
  30. <template #text>{{ model.follow ? '已监控' : '监控' }}</template>
  31. </TabActionItem>
  32. </template>
  33. </van-popover>
  34. </template>
  35. <script>
  36. import TabActionItem from '@/views/article/ui/TabActionItem.vue'
  37. import FollowPopoverContentCard from '@/views/article/ui/FollowPopoverContentCard.vue'
  38. import { useQuickMonitorModel } from '@/composables/quick-monitor/index'
  39. import { Popover } from 'vant'
  40. import { AppIcon } from '@/ui'
  41. import { reactive, toRefs, toRef } from 'vue'
  42. import { mapGetters } from 'vuex'
  43. import { LINKS } from '@/data'
  44. import { openAppOrWxPage } from '@/utils/'
  45. const confMap = {
  46. project: {
  47. key: '项目',
  48. pushActiveKey: 2,
  49. applyMoreSource: 'article_project_more',
  50. limitSource: 'article_project_limit',
  51. toPushSettingDialogMessage:
  52. '您可前往“工作台-商机-项目进度监控”查看项目最新招标/采购进度。',
  53. successDialogMessage: '监控成功,您可前往“工作台-商机-项目进度监控”查看',
  54. monitorListLink: LINKS.项目进度监控
  55. },
  56. ent: {
  57. key: '企业',
  58. pushActiveKey: 4,
  59. applyMoreSource: 'article_ent_more',
  60. limitSource: 'article_ent_limit',
  61. toPushSettingDialogMessage:
  62. '您可前往“工作台-商机-企业情报监控”查看项目最新招标/采购进度。',
  63. successDialogMessage: '监控成功,您可前往“工作台-商机-企业情报监控”查看',
  64. monitorListLink: LINKS.企业情报监控
  65. },
  66. client: {
  67. key: '业主',
  68. pushActiveKey: 3,
  69. applyMoreSource: 'article_client_more',
  70. limitSource: 'article_client_limit',
  71. toPushSettingDialogMessage:
  72. '您可前往“工作台-商机-业主监控”查看项目最新招标/采购进度。',
  73. successDialogMessage: '监控成功,您可前往“工作台-商机-业主监控”查看',
  74. monitorListLink: LINKS.业主监控
  75. }
  76. }
  77. export default {
  78. name: 'QuickMonitor',
  79. components: {
  80. [Popover.name]: Popover,
  81. FollowPopoverContentCard,
  82. TabActionItem,
  83. AppIcon
  84. },
  85. props: {
  86. id: {
  87. type: String,
  88. default: '',
  89. required: true
  90. },
  91. type: {
  92. type: String,
  93. default: 'project',
  94. validator(t) {
  95. return ['project', 'ent', 'client'].includes(t)
  96. }
  97. },
  98. // 是否使用popover
  99. popover: {
  100. type: Boolean,
  101. default: false
  102. },
  103. cache: {
  104. type: Boolean,
  105. default: false
  106. },
  107. // 默认doFetch请求
  108. auto: {
  109. type: Boolean,
  110. default: false
  111. },
  112. direction: {
  113. type: String,
  114. default: 'column',
  115. validator(d) {
  116. return ['row', 'column'].includes(d)
  117. }
  118. },
  119. placement: {
  120. type: String,
  121. default: 'top'
  122. },
  123. beforeAction: Function
  124. },
  125. setup(props, { emit }) {
  126. const useMonitor = useQuickMonitorModel({
  127. type: props.type,
  128. cache: props.cache,
  129. params: {
  130. id: props.id
  131. }
  132. })
  133. const { model, fid } = toRefs(reactive(useMonitor))
  134. const { follow } = toRef(model)
  135. const { doFetch, doChange } = useMonitor
  136. if (props.auto) {
  137. doFetch().then((res) => {
  138. emit('afterFetch', res)
  139. })
  140. }
  141. return {
  142. useMonitor,
  143. model,
  144. follow,
  145. fid,
  146. doFetch,
  147. doChange
  148. }
  149. },
  150. data() {
  151. return {
  152. showPopover: false
  153. // model: {
  154. // canFollow: false,
  155. // follow: false,
  156. // expands: {
  157. // surplus: 0,
  158. // used: 0
  159. // }
  160. // }
  161. }
  162. },
  163. computed: {
  164. ...mapGetters('user', ['isLogin', 'isMember', 'isBusiness']),
  165. isMemberOrBusiness() {
  166. return this.isMember || this.isBusiness
  167. },
  168. conf() {
  169. return confMap[this.type] || confMap.project
  170. },
  171. calcOffset() {
  172. if (this.placement === 'top-start') {
  173. return [5, 10]
  174. } else if (this.placement === 'top-end') {
  175. return [-5, 10]
  176. } else {
  177. return undefined
  178. }
  179. }
  180. },
  181. methods: {
  182. toProjectDetail() {
  183. const params = {
  184. fid: this.fid,
  185. sid: this.id
  186. }
  187. sessionStorage.setItem('bigvip-fid', JSON.stringify(params))
  188. openAppOrWxPage(LINKS.项目详情页)
  189. },
  190. toMonitorList() {
  191. openAppOrWxPage(this.conf.monitorListLink)
  192. this.showPopoverList(false)
  193. },
  194. applyMoreMonitor() {
  195. if (this.isMemberOrBusiness) {
  196. // 弹窗提示监控更多项目/企业/业主
  197. this.concatKfDialog({
  198. title: `申请监控更多${this.conf.key}`,
  199. message: `您可联系客服,申请升级产品套餐,监控更多${this.conf.key}`
  200. })
  201. } else {
  202. // 留资页面
  203. this.$leaveInfo.toLeaveInfoPage({
  204. source: `${this.$env.platform}_${this.conf.applyMoreSource}`
  205. })
  206. }
  207. this.showPopoverList(false)
  208. },
  209. async concatKfDialog({ message, title }) {
  210. try {
  211. await this.$dialog.alert({
  212. title: title || '',
  213. messageAlign: 'center',
  214. className: 'j-confirm-dialog',
  215. confirmButtonText: '联系客服',
  216. showCancelButton: true,
  217. cancelButtonText: '我再想想',
  218. message: message
  219. })
  220. // 联系客服
  221. openAppOrWxPage(LINKS.客服)
  222. } catch (error) {
  223. console.log('我再想想', error)
  224. }
  225. },
  226. async cancelMonitorDialog() {
  227. return await this.$dialog.alert({
  228. title: '确定不再监控?',
  229. messageAlign: 'center',
  230. className: 'j-confirm-dialog',
  231. confirmButtonText: '我再想想',
  232. showCancelButton: true,
  233. cancelButtonText: '确定取消',
  234. message: `取消监控,将错过${this.conf.key}最新动态推送`
  235. })
  236. },
  237. async cancelMonitor() {
  238. try {
  239. await this.cancelMonitorDialog()
  240. } catch (error) {
  241. this.doCancelMonitor()
  242. }
  243. },
  244. showPopoverList(f = false) {
  245. this.showPopover = f
  246. },
  247. async changePopoverState() {
  248. if (this.model.follow) {
  249. // 已监控
  250. if (this.popover) {
  251. this.showPopoverList(!this.showPopover)
  252. } else {
  253. this.doMonitor()
  254. }
  255. } else {
  256. this.doMonitor()
  257. }
  258. },
  259. async successMonitorAndToPushSettingDialog() {
  260. try {
  261. await this.$dialog.alert({
  262. title: '监控成功',
  263. messageAlign: 'center',
  264. className: 'j-confirm-dialog',
  265. confirmButtonText: '去开启',
  266. showCancelButton: true,
  267. cancelButtonText: '暂不开启',
  268. message: `${this.conf.toPushSettingDialogMessage}为保证您能及时获取新增监控信息推送,请前往开启推送提醒。`
  269. })
  270. // 去开启提醒
  271. this.$router.push({
  272. path: '/push/pushsetting',
  273. query: {
  274. active: this.conf.pushActiveKey
  275. }
  276. })
  277. } catch (error) {
  278. console.log('暂不开启推送提醒', error)
  279. }
  280. },
  281. // 监控
  282. /**
  283. * 监控操作业务流程
  284. * 0. 前置权益判断
  285. * 0.1 判断是否非大会员、非商机管理用户
  286. * > 否,留资弹窗
  287. * 1. 监控成功
  288. * 1.1 判断是否开启推送提醒
  289. * > 是,提醒开启推送提醒 success-monitor
  290. * > 否,toast 提醒监控成功 success-toast
  291. * 2. 监控失败
  292. * 2.1 超出可监控项目个数
  293. * 2.1.1 判断是否非大会员、非商机管理用户
  294. * > 是,弹窗提醒 max-monitor
  295. * > 否,留资弹窗
  296. * 2.2 其他错误,toast 提醒
  297. * @return {Promise<void>}
  298. */
  299. async doMonitor() {
  300. if (this.beforeAction) {
  301. const r = await this.beforeAction()
  302. if (!r) {
  303. return
  304. }
  305. }
  306. const loading = this.$toast.loading()
  307. // do something...
  308. try {
  309. const { success, msg, data } = await this.doChange()
  310. loading.clear()
  311. console.log(msg)
  312. if (success) {
  313. // 判断是否开启推送提醒
  314. if (data?.msg_open) {
  315. // 推送提醒已经开启
  316. this.$toast(this.conf.successDialogMessage)
  317. } else {
  318. // 提醒未开启
  319. this.successMonitorAndToPushSettingDialog()
  320. }
  321. } else {
  322. // 判断是否超出可监控项目个数
  323. if (data?.limit_status) {
  324. if (this.isMemberOrBusiness) {
  325. const count = data?.limit_status || 0
  326. this.concatKfDialog({
  327. title: `监控${this.conf.key}个数已达上限`,
  328. message: `您最多可监控${count}个${this.conf.key},可联系客服,申请监控更多${this.conf.key}`
  329. })
  330. } else {
  331. // 留资
  332. this.$leaveInfo.toLeaveInfoPage({
  333. source: `${this.$env.platform}_${this.conf.limitSource}`
  334. })
  335. }
  336. }
  337. // if (msg) {
  338. // this.$toast(msg)
  339. // }
  340. }
  341. this.syncValue(true)
  342. } catch (error) {
  343. loading.clear()
  344. }
  345. },
  346. // 取消监控
  347. async doCancelMonitor() {
  348. const loading = this.$toast.loading()
  349. const { success, msg } = await this.doChange()
  350. if (success) {
  351. console.log('取消监控成功')
  352. } else {
  353. console.log('取消监控失败', msg)
  354. }
  355. loading.clear()
  356. this.syncValue(false)
  357. },
  358. syncValue(v) {
  359. this.$emit('input', v)
  360. }
  361. }
  362. }
  363. </script>
  364. <style lang="scss" scoped>
  365. ::v-deep {
  366. .tab-action-item {
  367. height: 100%;
  368. }
  369. .icon-jiankong {
  370. color: #9b9ca3;
  371. }
  372. .icon-yijiankong {
  373. color: #ff9f40;
  374. }
  375. }
  376. </style>