feat(web-admin): add mp webview shell and /m/pl/plan static routes.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
c0721786ff
commit
8fbe0679c9
8 files changed
+238
No files matched your search
@@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<div class="mp-wv-root">
|
||||
<p v-if="phase === 'boot'" class="mp-wv-placeholder">加载中…</p>
|
||||
<p v-else-if="phase === 'need-mini'" class="mp-wv-placeholder">请从山峡化工小程序打开</p>
|
||||
<p v-else-if="phase === 'expired'" class="mp-wv-placeholder">登录已失效</p>
|
||||
<slot v-else />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import { useDictStore } from '@/store/modules/dict'
|
||||
import { mpWebviewApi } from '@/api/mp-webview'
|
||||
import { redirectToMiniLogin, stripMpTicketFromUrl } from '@/utils/mp-webview'
|
||||
|
||||
const JWX_SRC = 'https://res.wx.qq.com/open/js/jweixin-1.6.0.js'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const userStore = useUserStore()
|
||||
const dictStore = useDictStore()
|
||||
const phase = ref<'boot' | 'need-mini' | 'expired' | 'ready'>('boot')
|
||||
|
||||
function loadJweixin(): Promise<void> {
|
||||
if (typeof window === 'undefined') return Promise.resolve()
|
||||
const wxObj = (window as unknown as { wx?: { miniProgram?: unknown } }).wx
|
||||
if (wxObj?.miniProgram) return Promise.resolve()
|
||||
if (document.querySelector('script[data-mp-jweixin]')) return Promise.resolve()
|
||||
return new Promise((resolve) => {
|
||||
const script = document.createElement('script')
|
||||
script.src = JWX_SRC
|
||||
script.async = true
|
||||
script.setAttribute('data-mp-jweixin', '1')
|
||||
script.onload = () => resolve()
|
||||
script.onerror = () => resolve()
|
||||
document.head.appendChild(script)
|
||||
})
|
||||
}
|
||||
|
||||
async function bootstrap() {
|
||||
await loadJweixin()
|
||||
const ticket = String(route.query.mpTicket || '').trim()
|
||||
if (ticket) {
|
||||
try {
|
||||
const data = await mpWebviewApi.exchange(ticket)
|
||||
userStore.setToken(data.token, data.refreshToken)
|
||||
userStore.setUserInfo(data.userInfo)
|
||||
userStore.setLoginStatus(true)
|
||||
await dictStore.loadAllDict()
|
||||
const nextQuery = stripMpTicketFromUrl(route.path, { ...route.query })
|
||||
await router.replace({ path: route.path, query: nextQuery as Record<string, string> })
|
||||
phase.value = 'ready'
|
||||
} catch {
|
||||
phase.value = 'expired'
|
||||
redirectToMiniLogin()
|
||||
}
|
||||
return
|
||||
}
|
||||
if (userStore.isLogin) {
|
||||
phase.value = 'ready'
|
||||
return
|
||||
}
|
||||
phase.value = 'need-mini'
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
void bootstrap()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.mp-wv-root {
|
||||
--brand: #0a9f6d;
|
||||
box-sizing: border-box;
|
||||
min-height: 100vh;
|
||||
max-width: 480px;
|
||||
margin: 0 auto;
|
||||
padding: 12px 16px calc(24px + env(safe-area-inset-bottom));
|
||||
color: #1f2a26;
|
||||
background: #f5f8f7;
|
||||
}
|
||||
|
||||
.mp-wv-placeholder {
|
||||
margin: 48px 0 0;
|
||||
font-size: 14px;
|
||||
color: #6b7b74;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user