Browse Source

✨ feat: 限制应用跳转第三方页面

Pchen. 1 day ago
parent
commit
5290f31baa

+ 3 - 0
src/pages/Login/uniLogin/uniLogin.vue

@@ -44,6 +44,7 @@ import { ref, onMounted } from 'vue'
 import { Notification } from '@arco-design/web-vue'
 import { Notification } from '@arco-design/web-vue'
 import { useUserStore } from '@/store/modules/user'
 import { useUserStore } from '@/store/modules/user'
 import { isElectron } from '@/utils/electron'
 import { isElectron } from '@/utils/electron'
+import { showOpenInBrowserGuide } from '@/utils/pwaBrowserGuide'
 
 
 const userStore = useUserStore()
 const userStore = useUserStore()
 
 
@@ -74,6 +75,8 @@ const loadOptions = async () => {
 const GetLoginUrl = async (type) => {
 const GetLoginUrl = async (type) => {
     if (!isTypeEnabled(type))
     if (!isTypeEnabled(type))
         return requestFailed('该登录方式已关闭')
         return requestFailed('该登录方式已关闭')
+    if (showOpenInBrowserGuide({ feature: `${type === 'qq' ? 'QQ' : '微信'}快捷登录` }))
+        return
 
 
     try {
     try {
         changeLoading(true)
         changeLoading(true)

+ 3 - 0
src/pages/User/setting/components/social-bindings.vue

@@ -51,6 +51,7 @@ import { onBeforeMount, reactive, ref } from 'vue'
 import { getLoginUrl, getUniLoginOptions } from '@/api/login'
 import { getLoginUrl, getUniLoginOptions } from '@/api/login'
 import { useUserStore } from '@/store/modules/user'
 import { useUserStore } from '@/store/modules/user'
 import { isElectron } from '@/utils/electron'
 import { isElectron } from '@/utils/electron'
+import { showOpenInBrowserGuide } from '@/utils/pwaBrowserGuide'
 import { Message, Modal, Notification } from '@arco-design/web-vue'
 import { Message, Modal, Notification } from '@arco-design/web-vue'
 
 
 const userStore = useUserStore()
 const userStore = useUserStore()
@@ -96,6 +97,8 @@ const bind = async (type) => {
     Message.warning('该绑定方式已关闭')
     Message.warning('该绑定方式已关闭')
     return
     return
   }
   }
+  if (showOpenInBrowserGuide({ feature: `${type === 'qq' ? 'QQ' : '微信'}账号绑定` }))
+    return
 
 
   try {
   try {
     state.loadingType = type
     state.loadingType = type

+ 3 - 0
src/pages/store/goodsDetail/index.vue

@@ -144,6 +144,7 @@ import GoodsEmoji from '@/components/store/GoodsEmoji.vue'
 import StoreDetailSkeleton from '@/components/skeleton/StoreDetailSkeleton.vue'
 import StoreDetailSkeleton from '@/components/skeleton/StoreDetailSkeleton.vue'
 import { stockLabel, parseFeatures, decodeGoodsContent } from '@/utils/storeFormat'
 import { stockLabel, parseFeatures, decodeGoodsContent } from '@/utils/storeFormat'
 import { submitPayment } from '@/utils/payment'
 import { submitPayment } from '@/utils/payment'
+import { showOpenInBrowserGuide } from '@/utils/pwaBrowserGuide'
 
 
 const route = useRoute()
 const route = useRoute()
 const router = useRouter()
 const router = useRouter()
@@ -218,6 +219,8 @@ const submitOrder = async () => {
     payType.value = paymentMethods.value[0]?.type || ''
     payType.value = paymentMethods.value[0]?.type || ''
     return
     return
   }
   }
+  if (showOpenInBrowserGuide({ feature: '订单支付' }))
+    return
   const paymentWindow = window.open('', '_blank')
   const paymentWindow = window.open('', '_blank')
   if (!paymentWindow) {
   if (!paymentWindow) {
     Message.warning('浏览器拦截了支付页弹窗,请允许弹窗后重试')
     Message.warning('浏览器拦截了支付页弹窗,请允许弹窗后重试')

+ 3 - 0
src/pages/store/orders/orderDetail/index.vue

@@ -161,6 +161,7 @@ import {
   decodeGoodsContent
   decodeGoodsContent
 } from '@/utils/storeFormat'
 } from '@/utils/storeFormat'
 import { submitPayment } from '@/utils/payment'
 import { submitPayment } from '@/utils/payment'
+import { showOpenInBrowserGuide } from '@/utils/pwaBrowserGuide'
 
 
 const route = useRoute()
 const route = useRoute()
 const { id } = route.params
 const { id } = route.params
@@ -349,6 +350,8 @@ const pay = async () => {
     selectedPayType.value = availablePaymentMethods.value[0]?.type || ''
     selectedPayType.value = availablePaymentMethods.value[0]?.type || ''
     return
     return
   }
   }
+  if (showOpenInBrowserGuide({ feature: '订单支付' }))
+    return
   const paymentWindow = window.open('', '_blank')
   const paymentWindow = window.open('', '_blank')
   if (!paymentWindow) {
   if (!paymentWindow) {
     Message.warning('浏览器拦截了支付页弹窗,请允许弹窗后重试')
     Message.warning('浏览器拦截了支付页弹窗,请允许弹窗后重试')

+ 47 - 0
src/utils/pwaBrowserGuide.js

@@ -0,0 +1,47 @@
+import { Message, Modal } from '@arco-design/web-vue'
+
+let guideVisible = false
+
+export function isInstalledWebApp() {
+  if (typeof window === 'undefined') return false
+
+  return Boolean(
+    window.matchMedia?.('(display-mode: standalone)').matches ||
+    window.matchMedia?.('(display-mode: window-controls-overlay)').matches ||
+    window.navigator?.standalone === true
+  )
+}
+
+export function showOpenInBrowserGuide({
+  feature = '当前功能',
+  url = window.location.href
+} = {}) {
+  if (!isInstalledWebApp()) return false
+  if (guideVisible) return true
+
+  guideVisible = true
+  Modal.confirm({
+    title: '请前往浏览器操作',
+    content: `${feature}需要跳转到第三方页面。安装后的应用窗口可能无法完成授权或支付,请在浏览器打开当前页面后继续操作。`,
+    okText: '打开浏览器',
+    cancelText: '我知道了',
+    async onOk() {
+      try {
+        await window.navigator.clipboard?.writeText(url)
+        Message.success('页面链接已复制,可在浏览器中粘贴打开')
+      } catch (error) {
+        console.log(error)
+      }
+      window.open(url, '_blank', 'noopener')
+      guideVisible = false
+    },
+    onCancel() {
+      guideVisible = false
+    },
+    onClose() {
+      guideVisible = false
+    }
+  })
+
+  return true
+}