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", "refresherrefresh",
"scrolltolower", "scrolltolower",
"tabbar", "tabbar",
"unibest",
"uvui", "uvui",
"WechatMiniprogram" "WechatMiniprogram"
], ],
+1 -1
View File
@@ -14,7 +14,7 @@
'" />', '" />',
) )
</script> </script>
<title>unibest</title> <title></title>
<!--preload-links--> <!--preload-links-->
<!--app-context--> <!--app-context-->
</head> </head>
+1 -1
View File
@@ -3,7 +3,7 @@ import { defineUniPages } from '@uni-helper/vite-plugin-uni-pages'
export default defineUniPages({ export default defineUniPages({
globalStyle: { globalStyle: {
navigationStyle: 'default', navigationStyle: 'default',
navigationBarTitleText: 'unibest', navigationBarTitleText: '',
navigationBarBackgroundColor: '#f8f8f8', navigationBarBackgroundColor: '#f8f8f8',
navigationBarTextStyle: 'black', navigationBarTextStyle: 'black',
backgroundColor: '#FFFFFF', backgroundColor: '#FFFFFF',
+59 -4
View File
@@ -1,20 +1,37 @@
<script setup lang="ts"> <script setup lang="ts">
import { onLaunch, onShow, onHide } from '@dcloudio/uni-app' import { onLaunch, onShow, onHide } from '@dcloudio/uni-app'
import { useUserStore } from './store'
import { checkWithRedirectLogin, loginRoute } from './interceptors/route'
onLaunch(() => { onLaunch((options) => {
console.log('App Launch') 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(() => { onHide(() => {
console.log('App Hide') console.log('App Hide')
}) })
const userStore = useUserStore()
</script> </script>
<style lang="scss"> <style lang="scss">
/* 覆盖 uniapp 自带rpx效果 */ /* 覆盖 uniapp 自带rpx效果 */
html { html {
font-family: 'PingFang SC', 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 16px !important; font-size: 16px !important;
} }
/* stylelint-disable-next-line selector-type-no-unknown */ /* stylelint-disable-next-line selector-type-no-unknown */
@@ -72,4 +89,42 @@ image {
view { view {
box-sizing: border-box; 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> </style>
+1 -1
View File
@@ -1,3 +1,3 @@
export { routeInterceptor } from './route' export { routerBeforeEachConfig } from './route'
export { requestInterceptor } from './request' export { requestInterceptor } from './request'
export { prototypeInterceptor } from './prototype' export { prototypeInterceptor } from './prototype'
+56 -7
View File
@@ -5,10 +5,13 @@
* 我这里应为大部分都可以随便进入,所以使用黑名单 * 我这里应为大部分都可以随便进入,所以使用黑名单
*/ */
import { useUserStore } from '@/store' 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 export const loginRoute = '/pages/login/index'
const loginRoute = '/pages/login/index'
const isLogged = () => { const isLogged = () => {
const userStore = useUserStore() const userStore = useUserStore()
@@ -23,14 +26,14 @@ const navigateToInterceptor = {
invoke({ url }: { url: string }) { invoke({ url }: { url: string }) {
// console.log(url) // /pages/route-interceptor/index?name=feige&age=30 // console.log(url) // /pages/route-interceptor/index?name=feige&age=30
const path = url.split('?')[0] const path = url.split('?')[0]
let needLoginPages: string[] = [] let notNeedLoginPages: string[] = []
// 为了防止开发时出现BUG,这里每次都获取一下。生产环境可以移到函数外,性能更好 // 为了防止开发时出现BUG,这里每次都获取一下。生产环境可以移到函数外,性能更好
if (isDev) { if (isDev) {
needLoginPages = getNeedLoginPages() notNeedLoginPages = getNotNeedLoginPages()
} else { } else {
needLoginPages = _needLoginPages notNeedLoginPages = _notNeedLoginPages
} }
const isNeedLogin = needLoginPages.includes(path) const isNeedLogin = notNeedLoginPages.includes(path)
if (!isNeedLogin) { if (!isNeedLogin) {
return true return true
} }
@@ -51,3 +54,49 @@ export const routeInterceptor = {
uni.addInterceptor('redirectTo', navigateToInterceptor) 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 { createSSRApp } from 'vue'
import App from './App.vue' import App from './App.vue'
import store from './store' import store from './store'
import { routeInterceptor, requestInterceptor, prototypeInterceptor } from './interceptors' import { requestInterceptor, prototypeInterceptor, routerBeforeEachConfig } from './interceptors'
import 'virtual:uno.css' import 'virtual:uno.css'
import '@/style/index.scss' import '@/style/index.scss'
export function createApp() { export function createApp() {
const app = createSSRApp(App) const app = createSSRApp(App)
app.use(store) app.use(store)
app.use(routeInterceptor) // app.use(routeInterceptor)
app.use(requestInterceptor) app.use(requestInterceptor)
app.use(prototypeInterceptor) app.use(prototypeInterceptor)
setTimeout(() => {
routerBeforeEachConfig((app as any).router)
}, 0)
return { return {
app, app,
} }
-1
View File
@@ -1,6 +1,5 @@
<route lang="json5" type="page"> <route lang="json5" type="page">
{ {
needLogin: true,
style: { navigationBarTitleText: '分包页面 标题' }, style: { navigationBarTitleText: '分包页面 标题' },
} }
</route> </route>
+10 -10
View File
@@ -1,7 +1,7 @@
{ {
"globalStyle": { "globalStyle": {
"navigationStyle": "default", "navigationStyle": "default",
"navigationBarTitleText": "unibest", "navigationBarTitleText": "",
"navigationBarBackgroundColor": "#f8f8f8", "navigationBarBackgroundColor": "#f8f8f8",
"navigationBarTextStyle": "black", "navigationBarTextStyle": "black",
"backgroundColor": "#FFFFFF" "backgroundColor": "#FFFFFF"
@@ -50,14 +50,6 @@
] ]
}, },
"pages": [ "pages": [
{
"path": "pages/login/index",
"type": "home",
"style": {
"navigationBarTitleText": "登录",
"navigationStyle": "custom"
}
},
{ {
"path": "pages/invest/index", "path": "pages/invest/index",
"type": "home", "type": "home",
@@ -82,6 +74,15 @@
"navigationBarTitleText": "房屋" "navigationBarTitleText": "房屋"
} }
}, },
{
"path": "pages/login/index",
"type": "page",
"style": {
"navigationBarTitleText": "登录",
"navigationStyle": "custom"
},
"notNeedLogin": false
},
{ {
"path": "pages/my/index", "path": "pages/my/index",
"type": "page", "type": "page",
@@ -98,7 +99,6 @@
{ {
"path": "demo/index", "path": "demo/index",
"type": "page", "type": "page",
"needLogin": true,
"style": { "style": {
"navigationBarTitleText": "分包页面 标题" "navigationBarTitleText": "分包页面 标题"
} }
+20 -1
View File
@@ -1,9 +1,10 @@
<route lang="json5" type="home"> <route lang="json5">
{ {
style: { style: {
navigationBarTitleText: '登录', navigationBarTitleText: '登录',
navigationStyle: 'custom', navigationStyle: 'custom',
}, },
notNeedLogin: false,
} }
</route> </route>
<template> <template>
@@ -39,6 +40,7 @@
<view class="ml-auto mr-0 w-fit text-#04A9F9 text-14 p-15">忘记密码</view> <view class="ml-auto mr-0 w-fit text-#04A9F9 text-14 p-15">忘记密码</view>
<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))]" 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> </view>
@@ -53,6 +55,23 @@
<script lang="ts" setup> <script lang="ts" setup>
import NavBar from '@/components/NavBar.vue' 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> </script>
<style lang="scss"> <style lang="scss">
+12
View File
@@ -84,6 +84,7 @@
<view <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" 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> </view>
@@ -93,6 +94,17 @@
<script lang="ts" setup> <script lang="ts" setup>
import Avatar from '@/components/Avatar.vue' import Avatar from '@/components/Avatar.vue'
import NavBar from '@/components/NavBar.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> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
+1 -5
View File
@@ -15,10 +15,7 @@ export const useUserStore = defineStore(
const clearUserInfo = () => { const clearUserInfo = () => {
userInfo.value = { ...initState } userInfo.value = { ...initState }
} }
// 一般没有reset需求,不需要的可以删除
const reset = () => {
userInfo.value = { ...initState }
}
const isLogged = computed(() => !!userInfo.value.token) const isLogged = computed(() => !!userInfo.value.token)
return { return {
@@ -26,7 +23,6 @@ export const useUserStore = defineStore(
setUserInfo, setUserInfo,
clearUserInfo, clearUserInfo,
isLogged, isLogged,
reset,
} }
}, },
{ {
+2 -2
View File
@@ -4,10 +4,10 @@
// Generated by vite-plugin-uni-pages // Generated by vite-plugin-uni-pages
interface NavigateToOptions { interface NavigateToOptions {
url: "/pages/login/index" | url: "/pages/invest/index" |
"/pages/invest/index" |
"/pages/index/index" | "/pages/index/index" |
"/pages/house/index" | "/pages/house/index" |
"/pages/login/index" |
"/pages/my/index" | "/pages/my/index" |
"/pages-sub/demo/index"; "/pages-sub/demo/index";
} }
+36 -6
View File
@@ -74,14 +74,17 @@ export const getUrlObj = (url: string) => {
} }
/** /**
* 得到所有的需要登录的pages,包括主包和分包的 * 得到所有的需要登录的pages,包括主包和分包的
* 这里设计得通用一点,可以传递key作为判断依据,默认是 needLogin, 与 route-block 配对使用 * 这里设计得通用一点,可以传递key作为判断依据,默认是 notNeedLogin, 与 route-block 配对使用
* 如果没有传 key,则表示所有的pages,如果传递了 key, 则表示通过 key 过滤 * 如果没有传 key,则表示所有的pages,如果传递了 key, 则表示通过 key 过滤
*/ */
export const getAllPages = (key = 'needLogin') => { export const getAllPages = (key = 'notNeedLogin') => {
// 这里处理主包 // 这里处理主包
const mainPages = [ const mainPages = [
...pages ...pages
.filter((page) => !key || page[key]) .filter((page) => {
if (!key) return false
return page[key] === false
})
.map((page) => ({ .map((page) => ({
...page, ...page,
path: `/${page.path}`, path: `/${page.path}`,
@@ -103,7 +106,6 @@ export const getAllPages = (key = 'needLogin') => {
}) })
}) })
const result = [...mainPages, ...subPages] const result = [...mainPages, ...subPages]
console.log(subPackages)
// console.log(`getAllPages by ${key} result: `, result) // console.log(`getAllPages by ${key} result: `, result)
return result return result
} }
@@ -112,13 +114,14 @@ export const getAllPages = (key = 'needLogin') => {
* 得到所有的需要登录的pages,包括主包和分包的 * 得到所有的需要登录的pages,包括主包和分包的
* 只得到 path 数组 * 只得到 path 数组
*/ */
export const getNeedLoginPages = (): string[] => getAllPages('needLogin').map((page) => page.path) export const getNotNeedLoginPages = (): string[] =>
getAllPages('notNeedLogin').map((page) => page.path)
/** /**
* 得到所有的需要登录的pages,包括主包和分包的 * 得到所有的需要登录的pages,包括主包和分包的
* 只得到 path 数组 * 只得到 path 数组
*/ */
export const needLoginPages: string[] = getAllPages('needLogin').map((page) => page.path) export const notNeedLoginPages: string[] = getAllPages('notNeedLogin').map((page) => page.path)
/** /**
* 根据微信小程序当前环境,判断应该获取的BaseUrl * 根据微信小程序当前环境,判断应该获取的BaseUrl
@@ -177,3 +180,30 @@ export const getEnvBaseUploadUrl = () => {
return baseUploadUrl 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", "module": "ESNext",
"moduleResolution": "Node", "moduleResolution": "Node",
"resolveJsonModule": true, "resolveJsonModule": true,
"noImplicitThis": true, "noImplicitThis": false,
"allowSyntheticDefaultImports": true, "allowSyntheticDefaultImports": true,
"allowJs": true, "allowJs": true,
"sourceMap": true, "sourceMap": true,