fix: simplified store

This commit is contained in:
chansee97 2024-03-24 22:13:07 +08:00
parent 86a4e9b10b
commit d96ac8cf54
11 changed files with 119 additions and 92 deletions

View File

@ -3,7 +3,7 @@ import type { ProxyOptions } from 'vite'
/** 不同请求服务的环境配置 */
export const proxyConfig: Record<ServiceEnvType, ServiceEnvConfig> = {
dev: {
url: 'http://localhost:3000',
url: 'https://mock.apifox.com/m1/4071143-0-default',
urlPattern: '/url-pattern',
},
test: {
@ -11,7 +11,7 @@ export const proxyConfig: Record<ServiceEnvType, ServiceEnvConfig> = {
urlPattern: '/url-pattern',
},
prod: {
url: 'http://localhost:8080',
url: 'https://mock.apifox.com/m1/4071143-0-default',
urlPattern: '/url-pattern',
},
}

View File

@ -1,7 +1,8 @@
<script setup lang="ts">
import type { RouteLocationNormalized } from 'vue-router'
import { useAppStore, useTabStore } from '@/store'
import { NIcon } from 'naive-ui'
import { renderIcon } from '@/utils'
import { useAppStore, useTabStore } from '@/store'
const tabStore = useTabStore()
const appStore = useAppStore()
@ -90,6 +91,17 @@ function handleContextMenu(e: MouseEvent, route: RouteLocationNormalized) {
function onClickoutside() {
showDropdown.value = false
}
function renderDropTabsLabel(option: any) {
return option.meta.title
}
function renderDropTabsIcon(option: any) {
return renderIcon(option.meta.icon)!()
}
function handleDropTabs(key: string, option: any) {
router.push(option.path)
}
</script>
<template>
@ -121,6 +133,20 @@ function onClickoutside() {
<e-icon :icon="item.meta.icon" /> {{ item.meta.title }}
</div>
</n-tab>
<template #suffix>
<n-dropdown
:options="tabStore.allTabs"
:render-label="renderDropTabsLabel"
:render-icon="renderDropTabsIcon"
trigger="click"
size="small"
@select="handleDropTabs"
>
<n-button tertiary circle type="primary">
<i-icon-park-outline-application-menu />
</n-button>
</n-dropdown>
</template>
</n-tabs>
<n-dropdown
placement="bottom-start"

View File

@ -11,7 +11,7 @@ export function fetchPost(data: any) {
}
/* formPost方法测试 */
export function fetchFormPost(data: any) {
const methodInstance = alovaInstance.Post('/postAPI', data)
const methodInstance = alovaInstance.Post('/postFormAPI', data)
methodInstance.meta = {
isFormPost: true,
}
@ -49,10 +49,20 @@ export function dictData() {
export function getBlob() {
const methodInstance = blankInstance.Get('https://images.unsplash.com/photo-1663529628961-80aa6ebcd157?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=764&q=80')
methodInstance.meta = {
isDownload: true,
// 标识为bolb数据
isBlob: true,
}
return methodInstance
}
/* 带进度的下载文件 */
export function downloadFile(url: string) {
const methodInstance = blankInstance.Get(url, {
// 开启下载进度
enableDownload: true,
})
return methodInstance
}
/* 测试状态码500失败 */
export function FailedRequest() {
return alovaInstance.Get('/serverError')

View File

@ -63,7 +63,7 @@ export function createAlovaInstance(
if (status === 200) {
// 返回blob数据
if (method.meta?.isDownload)
if (method.meta?.isBlob)
return response.blob()
// 返回json数据

View File

@ -5,12 +5,8 @@ const { url, urlPattern } = proxyConfig[import.meta.env.MODE]
const isHttpProxy = import.meta.env.VITE_HTTP_PROXY === 'Y' || false
export const request = createAlovaInstance({
baseURL: isHttpProxy ? urlPattern : url,
})
export const alovaInstance = createAlovaInstance({
baseURL: 'https://mock.apifox.com/m1/4071143-0-default',
baseURL: isHttpProxy ? urlPattern : url,
})
export const blankInstance = createAlovaInstance({

View File

@ -4,20 +4,15 @@ import { fetchLogin, fetchUserInfo } from '@/service'
import { router } from '@/router'
import { local } from '@/utils'
const emptyInfo: Auth.UserInfo = {
id: 0,
userName: '',
nickName: '',
avatar: '',
role: 'user',
interface AuthStatus {
userInfo: Auth.UserInfo | null
token: string
}
export const useAuthStore = defineStore('auth-store', {
state: () => {
state: (): AuthStatus => {
return {
userInfo: local.get('userInfo') || emptyInfo,
userInfo: local.get('userInfo'),
token: local.get('token') || '',
refreshToken: local.get('refreshToken') || '',
loginLoading: false,
}
},
getters: {
@ -58,16 +53,12 @@ export const useAuthStore = defineStore('auth-store', {
/* 用户登录 */
async login(username: string, password: string) {
this.loginLoading = true
const { error, data } = await fetchLogin({ username, password })
if (error) {
this.loginLoading = false
if (error)
return
}
// 处理登录信息
await this.handleAfterLogin(data)
this.loginLoading = false
},
/* 登录后的处理函数 */
@ -91,7 +82,7 @@ export const useAuthStore = defineStore('auth-store', {
// 触发用户提示
window.$notification?.success({
title: '登录成功!',
content: `欢迎回来😊,${this.userInfo.nickName}!`,
content: `欢迎回来😊,${this.userInfo?.nickName}!`,
duration: 3000,
})
return
@ -108,7 +99,6 @@ export const useAuthStore = defineStore('auth-store', {
local.set('token', accessToken)
local.set('refreshToken', refreshToken)
this.token = accessToken
this.refreshToken = refreshToken
const { error, data } = await fetchUserInfo({ id })
if (error)
return catchSuccess

View File

@ -13,19 +13,17 @@ import { BasicLayout } from '@/layouts/index'
interface RoutesStatus {
isInitAuthRoute: boolean
menus: any
userRoutes: AppRoute.RowRoute[]
rowRoutes: AppRoute.RowRoute[]
activeMenu: string | null
authRouteMode: ImportMetaEnv['VITE_AUTH_ROUTE_MODE']
cacheRoutes: string[]
}
export const useRouteStore = defineStore('route-store', {
state: (): RoutesStatus => {
return {
userRoutes: [],
isInitAuthRoute: false,
menus: [],
rowRoutes: [],
activeMenu: null,
authRouteMode: import.meta.env.VITE_AUTH_ROUTE_MODE,
cacheRoutes: [],
}
},
@ -38,30 +36,12 @@ export const useRouteStore = defineStore('route-store', {
/* 删除后面添加的路由 */
router.removeRoute('appRoot')
},
/* 判断当前路由和子路由中是否存在为routeName的路由 */
hasPathinAllPath(routeName: string, userRoutes: AppRoute.Route) {
if (userRoutes.name === routeName)
return true
if (userRoutes.children && userRoutes.children.length !== 0) {
const arr: boolean[] = []
userRoutes.children.forEach((item) => {
arr.push(this.hasPathinAllPath(routeName, item))
})
return arr.some((item) => {
return item
})
}
return false
},
/* 设置当前高亮的菜单key */
setActiveMenu(key: string) {
this.activeMenu = key
},
/* 生成侧边菜单的数据 */
createMenus(userRoutes: AppRoute.RowRoute[]) {
this.userRoutes = userRoutes
const resultMenus = clone(userRoutes).map(i => construct(i)) as AppRoute.Route[]
/** 过滤不需要显示的菜单 */
const visibleMenus = resultMenus.filter(route => !route.meta.hide)
@ -139,7 +119,7 @@ export const useRouteStore = defineStore('route-store', {
}
})
},
createDynamicRoutes(routes: AppRoute.RowRoute[]) {
createRoutes(routes: AppRoute.RowRoute[]) {
const { hasPermission } = usePermission()
// 结构化meta字段
let resultRouter = clone(routes).map(i => construct(i)) as AppRoute.Route[]
@ -175,44 +155,38 @@ export const useRouteStore = defineStore('route-store', {
}
// 根据角色过滤后的插入根路由中
appRootRoute.children = resultRouter as unknown as RouteRecordRaw[]
return appRootRoute
},
/* 初始化动态路由 */
async initDynamicRoute() {
// 根据用户id来获取用户的路由
const userInfo = local.get('userInfo')
if (!userInfo || !userInfo.id)
return
const { data } = await fetchUserRoutes({
id: userInfo.id,
})
if (!data)
return
// 根据用户返回的路由表来生成真实路由
const appRoutes = this.createDynamicRoutes(data)
// 生成侧边菜单
this.createMenus(data)
// 插入路由表
router.addRoute(appRoutes)
},
/* 初始化静态路由 */
initStaticRoute() {
// 根据静态路由表来生成真实路由
const appRoutes = this.createDynamicRoutes(staticRoutes)
// 生成侧边菜单
this.createMenus(staticRoutes)
// 插入路由表
router.addRoute(appRoutes)
router.addRoute(appRootRoute)
},
async initRouteInfo() {
if (import.meta.env.VITE_AUTH_ROUTE_MODE === 'dynamic') {
// 根据用户id来获取用户的路由
const userInfo = local.get('userInfo')
if (!userInfo || !userInfo.id)
return
const { data } = await fetchUserRoutes({
id: userInfo.id,
})
if (!data)
return
this.rowRoutes = data
}
else {
this.rowRoutes = staticRoutes
}
},
async initAuthRoute() {
this.isInitAuthRoute = false
if (this.authRouteMode === 'dynamic')
await this.initDynamicRoute()
else this.initStaticRoute()
// 初始化路由信息
await this.initRouteInfo()
// 生成真实路由并插入
this.createRoutes(this.rowRoutes)
// 生成侧边菜单
this.createMenus(this.rowRoutes)
this.isInitAuthRoute = true
},

View File

@ -14,6 +14,9 @@ export const useTabStore = defineStore('tab-store', {
currentTabPath: '',
}
},
getters: {
allTabs: state => [...state.pinTabs, ...state.tabs],
},
actions: {
addTab(route: RouteLocationNormalized) {
// 根据meta确定是否不添加可用于错误页,登录页等

View File

@ -20,7 +20,7 @@ declare namespace Service {
successCode?: number | string
}
type RequestErrorType = 'Alova' | 'Response' | 'Business'
type RequestErrorType = 'Response' | 'Business'
type RequestCode = string | number
interface RequestError {

View File

@ -1,5 +1,6 @@
<script setup lang="ts">
import type { FormInst } from 'naive-ui'
import { useRequest } from 'alova'
import { local } from '@/utils'
import { useAuthStore } from '@/store'
@ -34,20 +35,23 @@ const formValue = ref({
code: '1234',
})
const isRemember = ref(false)
const isLoading = ref(false)
const formRef = ref<FormInst | null>(null)
function handleLogin() {
formRef.value?.validate((errors) => {
formRef.value?.validate(async (errors) => {
if (errors)
return
isLoading.value = true
const { account, pwd } = formValue.value
if (isRemember.value)
local.set('login_account', { account, pwd })
else local.remove('login_account')
authStore.login(account, pwd)
await authStore.login(account, pwd)
isLoading.value = false
})
}
function checkUserAccount() {
@ -95,7 +99,7 @@ checkUserAccount()
忘记密码
</n-button>
</div>
<n-button block type="primary" size="large" :loading="authStore.loginLoading" @click="handleLogin">
<n-button block type="primary" size="large" :loading="isLoading" @click="handleLogin">
登录
</n-button>
<n-button type="primary" text @click="toOtherForm('register')">

View File

@ -5,6 +5,7 @@ import {
FailedResponse,
FailedResponseWithoutTip,
dictData,
downloadFile,
expiredTokenRequest,
fetachGet,
fetchDelete,
@ -17,14 +18,14 @@ import {
} from '@/service'
const msg = ref()
const { data, send } = useRequest(fetachGet({ a: 112211 }), {
const { data: fetachGetData, send: sendFetachGet } = useRequest(fetachGet({ a: 112211 }), {
// immediatefalse
immediate: false,
})
function handleRequestHook() {
send()
msg.value = data.value
sendFetachGet()
msg.value = fetachGetData.value
}
function pinterEnv() {
msg.value = import.meta.env
@ -126,6 +127,17 @@ function getBlobFile() {
document.body.removeChild(eleLink)
})
}
//
const downloadPath = ref('https://suqiqi.oss-cn-beijing.aliyuncs.com/test/video/1.mp4')
const { downloading, abort: abortDownloadFile, send: sendDownloadFile } = useRequest(downloadFile(downloadPath.value), {
// immediatefalse
immediate: false,
})
const downloadProcess = computed(() => {
if (!downloading.value.loaded)
return 0
return Math.floor(downloading.value.loaded / downloading.value.total * 100)
})
</script>
<template>
@ -180,6 +192,18 @@ function getBlobFile() {
click
</n-button>
</n-descriptions-item>
<n-descriptions-item label="带进度的下载文件" span="3">
<n-input v-model:value="downloadPath" />
<div>文件大小{{ downloading.total }}B</div>
<div>已下载{{ downloading.loaded }}B</div>
<n-progress type="line" indicator-placement="inside" :percentage="downloadProcess" />
<n-button strong secondary @click="sendDownloadFile">
开始下载
</n-button>
<n-button strong secondary type="warning" @click="abortDownloadFile">
中断下载
</n-button>
</n-descriptions-item>
<n-descriptions-item label="转换请求数据">
<n-button strong secondary type="success" @click="getDictData">
click