feat: 路由管理

This commit is contained in:
anonymous
2024-12-27 14:37:17 +08:00
parent 8d6a9f3eec
commit 06679d50e2
15 changed files with 208 additions and 43 deletions
-1
View File
@@ -44,7 +44,6 @@
"refresherrefresh",
"scrolltolower",
"tabbar",
"unibest",
"uvui",
"WechatMiniprogram"
],
+1 -1
View File
@@ -14,7 +14,7 @@
'" />',
)
</script>
<title>unibest</title>
<title></title>
<!--preload-links-->
<!--app-context-->
</head>
+1 -1
View File
@@ -3,7 +3,7 @@ import { defineUniPages } from '@uni-helper/vite-plugin-uni-pages'
export default defineUniPages({
globalStyle: {
navigationStyle: 'default',
navigationBarTitleText: 'unibest',
navigationBarTitleText: '',
navigationBarBackgroundColor: '#f8f8f8',
navigationBarTextStyle: 'black',
backgroundColor: '#FFFFFF',
+59 -4
View File
@@ -1,20 +1,37 @@
<script setup lang="ts">
import { onLaunch, onShow, onHide } from '@dcloudio/uni-app'
import { useUserStore } from './store'
import { checkWithRedirectLogin, loginRoute } from './interceptors/route'
onLaunch(() => {
console.log('App Launch')
onLaunch((options) => {
if (checkWithRedirectLogin(options.path)) {
uni.reLaunch({
url: loginRoute,
query: {
redirect: options.path,
},
})
}
})
onShow(() => {
console.log('App Show')
onPageNotFound(() => {
console.log(1)
uni.reLaunch({
url: '/',
})
})
onHide(() => {
console.log('App Hide')
})
const userStore = useUserStore()
</script>
<style lang="scss">
/* 覆盖 uniapp 自带rpx效果 */
html {
font-family: 'PingFang SC', 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 16px !important;
}
/* stylelint-disable-next-line selector-type-no-unknown */
@@ -72,4 +89,42 @@ image {
view {
box-sizing: border-box;
}
uni-modal {
.uni-modal {
@apply max-w-345 rounded-16;
}
.uni-modal__hd {
@apply p-0;
}
.uni-modal__title {
@apply p-16 text-left text-16 font-600;
}
.uni-modal__bd {
@apply mb-16 px-16 pt-0 text-left text-14 font-medium text-#666;
}
.uni-modal__btn {
@apply px-16 py-8 flex-none rounded-full shadow-none text-14;
&::after {
content: none;
}
&.uni-modal__btn_primary {
@apply ml-8 bg-gray-200 !text-black;
}
}
.uni-modal__ft {
@apply justify-end p-16 leading-normal;
&::after {
content: none;
}
}
}
</style>
+1 -1
View File
@@ -1,3 +1,3 @@
export { routeInterceptor } from './route'
export { routerBeforeEachConfig } from './route'
export { requestInterceptor } from './request'
export { prototypeInterceptor } from './prototype'
+56 -7
View File
@@ -5,10 +5,13 @@
* 我这里应为大部分都可以随便进入,所以使用黑名单
*/
import { useUserStore } from '@/store'
import { getNeedLoginPages, needLoginPages as _needLoginPages } from '@/utils'
import {
getNotNeedLoginPages as _getNotNeedLoginPages,
notNeedLoginPages as _notNeedLoginPages,
} from '@/utils'
import type { Router } from 'vue-router'
// TODO Check
const loginRoute = '/pages/login/index'
export const loginRoute = '/pages/login/index'
const isLogged = () => {
const userStore = useUserStore()
@@ -23,14 +26,14 @@ const navigateToInterceptor = {
invoke({ url }: { url: string }) {
// console.log(url) // /pages/route-interceptor/index?name=feige&age=30
const path = url.split('?')[0]
let needLoginPages: string[] = []
let notNeedLoginPages: string[] = []
// 为了防止开发时出现BUG,这里每次都获取一下。生产环境可以移到函数外,性能更好
if (isDev) {
needLoginPages = getNeedLoginPages()
notNeedLoginPages = getNotNeedLoginPages()
} else {
needLoginPages = _needLoginPages
notNeedLoginPages = _notNeedLoginPages
}
const isNeedLogin = needLoginPages.includes(path)
const isNeedLogin = notNeedLoginPages.includes(path)
if (!isNeedLogin) {
return true
}
@@ -51,3 +54,49 @@ export const routeInterceptor = {
uni.addInterceptor('redirectTo', navigateToInterceptor)
},
}
export const getNotNeedLoginPages = () => {
let notNeedLoginPages: string[] = []
if (isDev) {
notNeedLoginPages = _getNotNeedLoginPages()
} else {
notNeedLoginPages = _notNeedLoginPages
}
return notNeedLoginPages
}
export const checkLoginUrl = (url: string) => {
const path = url.split('?')[0]
const isNotNeedLogin = getNotNeedLoginPages().includes(path)
return isNotNeedLogin
}
export const checkWithRedirectLogin = (url: string) => {
const isNotNeedLogin = checkLoginUrl(url)
if (!isNotNeedLogin) {
return !isLogged()
}
return false
}
export const checkNotFound = (url: string) => {
const isNotNeedLogin = checkLoginUrl(url)
if (!isNotNeedLogin) {
return !isLogged()
}
return false
}
export const routerBeforeEachConfig = (router: Router) => {
router.beforeEach((to, from, next) => {
if (checkWithRedirectLogin(to.path)) {
return next({
path: loginRoute,
query: {
redirect: to.fullPath,
},
})
}
return next()
})
}
+8 -2
View File
@@ -1,16 +1,22 @@
import { createSSRApp } from 'vue'
import App from './App.vue'
import store from './store'
import { routeInterceptor, requestInterceptor, prototypeInterceptor } from './interceptors'
import { requestInterceptor, prototypeInterceptor, routerBeforeEachConfig } from './interceptors'
import 'virtual:uno.css'
import '@/style/index.scss'
export function createApp() {
const app = createSSRApp(App)
app.use(store)
app.use(routeInterceptor)
// app.use(routeInterceptor)
app.use(requestInterceptor)
app.use(prototypeInterceptor)
setTimeout(() => {
routerBeforeEachConfig((app as any).router)
}, 0)
return {
app,
}
-1
View File
@@ -1,6 +1,5 @@
<route lang="json5" type="page">
{
needLogin: true,
style: { navigationBarTitleText: '分包页面 标题' },
}
</route>
+10 -10
View File
@@ -1,7 +1,7 @@
{
"globalStyle": {
"navigationStyle": "default",
"navigationBarTitleText": "unibest",
"navigationBarTitleText": "",
"navigationBarBackgroundColor": "#f8f8f8",
"navigationBarTextStyle": "black",
"backgroundColor": "#FFFFFF"
@@ -50,14 +50,6 @@
]
},
"pages": [
{
"path": "pages/login/index",
"type": "home",
"style": {
"navigationBarTitleText": "登录",
"navigationStyle": "custom"
}
},
{
"path": "pages/invest/index",
"type": "home",
@@ -82,6 +74,15 @@
"navigationBarTitleText": "房屋"
}
},
{
"path": "pages/login/index",
"type": "page",
"style": {
"navigationBarTitleText": "登录",
"navigationStyle": "custom"
},
"notNeedLogin": false
},
{
"path": "pages/my/index",
"type": "page",
@@ -98,7 +99,6 @@
{
"path": "demo/index",
"type": "page",
"needLogin": true,
"style": {
"navigationBarTitleText": "分包页面 标题"
}
+20 -1
View File
@@ -1,9 +1,10 @@
<route lang="json5" type="home">
<route lang="json5">
{
style: {
navigationBarTitleText: '登录',
navigationStyle: 'custom',
},
notNeedLogin: false,
}
</route>
<template>
@@ -39,6 +40,7 @@
<view class="ml-auto mr-0 w-fit text-#04A9F9 text-14 p-15">忘记密码</view>
<view
class="mt-30 text-center py-12 rounded-full mx-15 text-15 text-white bg-[linear-gradient(45deg,rgba(59,129,243,0.5),rgba(55,230,236,0.51))]"
@click="handleLogin"
>
登录
</view>
@@ -53,6 +55,23 @@
<script lang="ts" setup>
import NavBar from '@/components/NavBar.vue'
import { useUserStore } from '@/store/user'
const userStore = useUserStore()
let redirect = '/'
onLoad((options) => {
redirect = options.redirect ?? '/'
})
const handleLogin = () => {
userStore.setUserInfo({
token: '123456',
})
uni.reLaunch({
url: redirect,
})
}
</script>
<style lang="scss">
+12
View File
@@ -84,6 +84,7 @@
<view
class="mt-50 mx-auto w-294 bg-[linear-gradient(45deg,#3B81F3,#37E6EC)] rounded-full text-center text-14 text-white py-15 mt-15"
@click="handleLogout"
>
退出登录
</view>
@@ -93,6 +94,17 @@
<script lang="ts" setup>
import Avatar from '@/components/Avatar.vue'
import NavBar from '@/components/NavBar.vue'
import { loginRoute } from '@/interceptors/route'
import { useUserStore } from '@/store/user'
const userStore = useUserStore()
const handleLogout = () => {
userStore.clearUserInfo()
uni.reLaunch({
url: loginRoute,
})
}
</script>
<style lang="scss" scoped>
+1 -5
View File
@@ -15,10 +15,7 @@ export const useUserStore = defineStore(
const clearUserInfo = () => {
userInfo.value = { ...initState }
}
// 一般没有reset需求,不需要的可以删除
const reset = () => {
userInfo.value = { ...initState }
}
const isLogged = computed(() => !!userInfo.value.token)
return {
@@ -26,7 +23,6 @@ export const useUserStore = defineStore(
setUserInfo,
clearUserInfo,
isLogged,
reset,
}
},
{
+2 -2
View File
@@ -4,10 +4,10 @@
// Generated by vite-plugin-uni-pages
interface NavigateToOptions {
url: "/pages/login/index" |
"/pages/invest/index" |
url: "/pages/invest/index" |
"/pages/index/index" |
"/pages/house/index" |
"/pages/login/index" |
"/pages/my/index" |
"/pages-sub/demo/index";
}
+36 -6
View File
@@ -74,14 +74,17 @@ export const getUrlObj = (url: string) => {
}
/**
* 得到所有的需要登录的pages,包括主包和分包的
* 这里设计得通用一点,可以传递key作为判断依据,默认是 needLogin, 与 route-block 配对使用
* 这里设计得通用一点,可以传递key作为判断依据,默认是 notNeedLogin, 与 route-block 配对使用
* 如果没有传 key,则表示所有的pages,如果传递了 key, 则表示通过 key 过滤
*/
export const getAllPages = (key = 'needLogin') => {
export const getAllPages = (key = 'notNeedLogin') => {
// 这里处理主包
const mainPages = [
...pages
.filter((page) => !key || page[key])
.filter((page) => {
if (!key) return false
return page[key] === false
})
.map((page) => ({
...page,
path: `/${page.path}`,
@@ -103,7 +106,6 @@ export const getAllPages = (key = 'needLogin') => {
})
})
const result = [...mainPages, ...subPages]
console.log(subPackages)
// console.log(`getAllPages by ${key} result: `, result)
return result
}
@@ -112,13 +114,14 @@ export const getAllPages = (key = 'needLogin') => {
* 得到所有的需要登录的pages,包括主包和分包的
* 只得到 path 数组
*/
export const getNeedLoginPages = (): string[] => getAllPages('needLogin').map((page) => page.path)
export const getNotNeedLoginPages = (): string[] =>
getAllPages('notNeedLogin').map((page) => page.path)
/**
* 得到所有的需要登录的pages,包括主包和分包的
* 只得到 path 数组
*/
export const needLoginPages: string[] = getAllPages('needLogin').map((page) => page.path)
export const notNeedLoginPages: string[] = getAllPages('notNeedLogin').map((page) => page.path)
/**
* 根据微信小程序当前环境,判断应该获取的BaseUrl
@@ -177,3 +180,30 @@ export const getEnvBaseUploadUrl = () => {
return baseUploadUrl
}
export function mergeStep(wrapped: (...rest: any[]) => Promise<any>) {
let _mergeStepRequestInstance: any = null
return async function (...args) {
if (this?._mergeStepRequestInstance ?? _mergeStepRequestInstance)
return this?._mergeStepRequestInstance ?? _mergeStepRequestInstance
if (this) {
this._mergeStepRequestInstance = wrapped.apply(this, args)
} else {
_mergeStepRequestInstance = wrapped(...args)
}
if (
Object.prototype.toString.call(
this?._mergeStepRequestInstance ?? _mergeStepRequestInstance,
) === '[object Promise]'
) {
;(this?._mergeStepRequestInstance ?? _mergeStepRequestInstance).finally(() => {
if (this?._mergeStepRequestInstance) {
this._mergeStepRequestInstance = null
} else {
_mergeStepRequestInstance = null
}
})
}
return _mergeStepRequestInstance
}
}
+1 -1
View File
@@ -5,7 +5,7 @@
"module": "ESNext",
"moduleResolution": "Node",
"resolveJsonModule": true,
"noImplicitThis": true,
"noImplicitThis": false,
"allowSyntheticDefaultImports": true,
"allowJs": true,
"sourceMap": true,